Learning goals of the first week

  1. What are R, RStudio, and Git?
  2. How to use R as a basic calculator?
  3. What are Objects in R?
  4. Something about R Data structures
    • Vectors
    • Matrices
    • Data frames
    • Arrays
    • Lists
  5. Selecting Elements in a vector, matrix or data frame
  6. Working with data frames
    • Loading data
    • Manipulating data
  7. Calculating Measures of Central Tendency and Variability
  8. Plotting data and saving plots

What are R, RStudio, and Git?

What is R?

R is a programming language designed to help you perform statistical analysis, create graphics, and later on write your own statistical software. R is becoming increasingly popular and knowledge of R will help you on the job market. R is probably the most versatile statistical tool out there (and it’s free and open-source so you can literally use it anywhere). It is for example used in all fields of academia, from biology to economics, and outside academia including

  • Wallstreet
  • The Economist
  • BBC
  • Google Analytics
  • NY Times graphics department

What is RStudio?

RStudio is a great graphical user interface for R. In recent years, a growing number of features have been added to this graphical user interface, which makes it the preferred choice for learning R, especially among beginners. You can think about it as R being the engine of the car and RStudio being the dashboard.

What are RStudio Projects?

RStudio projects make it straightforward to divide your work into multiple contexts, each with its own working directory, workspace, history, and source documents. A project is basically a folder on your computer that holds all the files relevant to a particular piece of work. Working in RStudio Projects has multiple advantages:

  • Once an RStudio Project is set up, you do not have to worry about your working directory anymore.
  • When opening an RStudio Project, a new R session (process) is started. This makes sure that things you do in different projects do not mess up.
  • You can open and work with multiple RStudio projects at the same time.
  • RStudio projects can easily be exported to and imported from GitHub.

What are Git and GitHub?

Git is a version control system that makes it easy to track changes and work on code collaboratively. GitHub is a hosting service for git. You can think of it as a public Dropbox for code but on steroids. With version control, you will build your projects step-by-step, be able to come back to any version of the project, and accompany everything with human-readable messages.

As a student, you even get unlimited private repositories which you can use if you don’t feel like sharing your code with the rest of the world (yet). We will use private repositories to distribute code and assignments to you. And you will use it to keep track of your code and collaborate in teams.

With git, writing code for a project will look somewhat like this:

What is a Git Repository?

A Git repository is a space where you store and manage a project. It contains all of your project’s files and stores each file’s revision history. It’s common to refer to a repository as a repo.

We will you one repository for each lab and one repository for each homework assignment. You can directly import (“pull”) repositories via RStudio and save them on your computer. If you changed something in your project, you can easily upload (“push”) the new version to GitHub. GitHub will keep track of all changes you made over time within your project.

Workflow overview

Our workflow will appear a bit tricky at the beginning but we are sure that you will handle it with ease very soon. We assume that by now you downloaded and installed R and Rstudio and have your personal GitHub account.

The course has its own page on GitHub, you can find it here: https://github.com/uni-mannheim-qm-2022. This is the place where you can find all relevant material for the lab sessions. It is also the place where you download and hand in your homework assignments.

So how does this work?

Get the URL of the repo for the current week

Go to https://github.com/uni-mannheim-qm-2022 and click on the repository for the current week (this week, this is called week01_introduction). Now, click on the green Clone or download button and select Use HTTPS (this might already be selected by default, and if it is, you’ll see the text Clone with HTTPS as in the image below). Click on the clipboard icon to copy the repo URL.

Import the repository in RStudio

  1. Open RStudio.
  2. Click on File on the top bar and select New Project....

  1. Select Version Control.
  2. In the next window, select Git.
  3. In the final window, paste the repo URL you grabbed from GitHub in the Repository URL window. Click on Browse to select the folder on your computer where you want to store the project.
  4. Click on Create Project.

Get working

  1. Open the .Rmd file that is stored in the project (in week 1, this is called QM2022_Week01.Rmd).

The RStudio interface

The RStudio interface has four panes:

  • Editor: This is were you usually code. You can either use .Rmd (R Markdown) or .R (plain R code) files.
  • Console: This is where the results appear once you execute your R-code. You can also directly type R-code into the console and execute it. However, we cannot save this code which is why we usually work in the Editor.
  • Environment: Here you have an overview over all the objects currently loaded in your environment. You will learn more about objects later in the course.
  • Files, Plots, Packages, Help, Viewer: Plots and other things will appear here, don’t worry too much about it for the moment.

R as a basic calculator

Enough preparation, let’s finally dive into R!

R can perform basic math operations. Here are some examples:

1 + 1
[1] 2

Some more calculations:

2 - 3
[1] -1
4 * 5
[1] 20
2^2
[1] 4
4 / 2
[1] 2
2^(1 / 2)
[1] 1.414214

If you place parentheses correctly, R incorporates the order of operations.

((2 + 2) * 2)^2
[1] 64

This should give the same result as before.

(4 * 2)^2
[1] 64

But this of course gives a different result:

(2 + 2 * 2)^2
[1] 36

You can also use other math functions you know from your calculator:

this is \(\sqrt{2}\)

sqrt(2)
[1] 1.414214

when you do not specify the base, R uses the natural log with base \(e\), i.e. \(\log_e(10)\)

log(10)
[1] 2.302585

but R can also use a different (virtually any) base, e.g. \(\log_{10}(10)\)

log(10, base = 10)
[1] 1

or with base = 5, i.e. \(\log_5(10)\)

log(10, 5)
[1] 1.430677

Pro tip: Always close your parentheses!

  • If you encounter an error when running your code, it is often a missing parenthesis, brace or bracket.
  • RStudio highlights your paired parenthesis. This is really nice and helpful!

Make use of comments

It is hard to understand pure code, especially for someone who did not write it (and future-you will also have a hard time to understand it).

Pro tip: Add comments to your code, describing what you are doing and why you are doing it.

With comments:

  • Other people can understand your code (for example us when we are going through your Homework assignments or your classmates when you are talking about your work).
  • You can remember what you were doing when you reopen your code after weeks (e.g., to prepare the data essay at the end of the semester).

So how can I add comments?

  • Begin a line with a # symbol,
  • Everything on that line after the # will be commented out.
  • This means if you send the script to the R console the console will not run these lines.
# this is a comment

1 + 1 # This line runs
[1] 2
# 1 + 1 This line does not run
  • Indent your scripts (both code and comments) using spaces so that they are readable.
  • Try to code according to Google’s R Style Guide.

Good coding style is like using correct punctuation.
Youcanmanagewithoutitbutitsuremakesthingseasiertoread.. – Hadley Wickham

Objects in R

But I already do have a calculator. Why do I need R?

R is so much more! R is an object-oriented programming language.

What is an “object” in R?

  • An object is a form to store the data you want to use.

What kind of data can I store as an object?

  • In R there are three main types of data you can store:
    • Numeric (numbers)
    • Character (letters/words/sentences/texts, called strings)
    • Logical (TRUE/FALSE statements)
  • These are the types you will often encounter.
  • However, there are many other possible types.

So how can I get information into an object?

  • Store an object by using <- as assignment operator

Examples:

lucky_number <-
 
# Now we created an (numeric) object called "lucky_number"

lucky_number
Error: object 'lucky_number' not found

The class() command lets us check the type of an object:

lucky_number <-

class(lucky_number)
Error: object 'lucky_number' not found

Let’s see how this works live, this time with a character object:

firstname <- "" # This is a character object

firstname
[1] ""
class(firstname)
[1] "character"
lastname <- ""

lastname
[1] ""

Data Structures

What kind of data can I store in R? Different types of objects that can contain different types and sets of data:

  • Scalar: numbers, characters, logical values
  • Vector: sets of scalars (thus, numbers, characters, logical)
  • Matrix: two-dimensional set of scalars of same type
  • Data frame: collections of vectors of (possibly) different types
  • Array: multidimensional set of scalars of same type
  • List: combinations of scalars, vectors, matrices…

We will go through all of these object types below. On top of that we will also learn how to calculate the measures of central tendency and variability with vectors.

Data Structures - Vectors

Let’s start with vectors. We want a vector of the numbers 1, 2, 3, 4 and 5. How do I assign this set of numbers to a vector?

The c() function combines single values to a vector:

example_vec <- c(1, 2, 3, 4, 5)

example_vec
[1] 1 2 3 4 5

This also works for characters/strings:

country_code <- c("DE", "FR", "NL", "US", "UK")

country_code
[1] "DE" "FR" "NL" "US" "UK"

And it also works for a combination of numbers and characters:

example_vec2 <- c("Welcome", "to", "the", "lab", "in", "A", 5)

example_vec2
[1] "Welcome" "to"      "the"     "lab"     "in"      "A"       "5"      

What if we start with numbers?

example_vec3 <- c(1, 2, 3, 4, 5, "R can count!")

example_vec3
[1] "1"            "2"            "3"            "4"            "5"            "R can count!"

Note that if you have a character field in your vector, R will turn ALL values into character data! (You can see that by the quotes around the values)

Let’s check the type of data by using the class() command on example_vec3.

example_vec3 <- c(1, 2, 3, 4, 5, "R can count!")

class(example_vec3)
[1] "character"

You can use mathematical functions on each element in numeric vectors/matrices etc.

example_vec <- c(1, 2, 3, 4, 5)

sqrt(example_vec) # Take the square root of each element in example_vec
[1] 1.000000 1.414214 1.732051 2.000000 2.236068

What about multiplication?

example_vec <- c(1, 2, 3, 4, 5)

example_vec * 10
[1] 10 20 30 40 50

There are also some functions that you can use on the whole vector.

example_vec <- c(1, 2, 3, 4, 5)

sum(example_vec) # Question: What does sum() do?
[1] 15
length(example_vec) # Question: What does length() do?
[1] 5

Data Structures - Matrices

Matrices in R are two-dimensional table objects. In R, matrices are always row by column. Like roller coaster, Roman Catholic or Ray Charles).

In a matrix, all data must be of the same type. If you mix numeric and character entries, the matrix will be all character just like in a vector.

How do I create a matrix in R?

example_mat1 <- matrix(c(1, 2, 3, 4, 5, 6),
  nrow = 3,
  ncol = 2
)

example_mat1 # How did R fill the numbers in the matrix?
     [,1] [,2]
[1,]    1    4
[2,]    2    5
[3,]    3    6

You could also change the options an let R fill the matrix by rows (instead of columns):

example_mat2 <- matrix(c(1, 2, 3, 4, 5, 6),
  nrow = 3,
  ncol = 2,
  byrow = T
)

example_mat2 # See the difference?
     [,1] [,2]
[1,]    1    2
[2,]    3    4
[3,]    5    6

Or you could create a matrix from different vectors by using column-bind on two or more vectors. It works similar to the c() function but with vectors as input instead of scalars.

Let’s first create two vectors of the same length:

vec1 <- c(1, 2, 3, 4, 5, 6)

vec2 <- c(7, 8, 9, 10, 11, 12)

# And now column-bind - cbind() - the two vectors.

example_mat3 <- cbind(vec1, vec2)

example_mat3
     vec1 vec2
[1,]    1    7
[2,]    2    8
[3,]    3    9
[4,]    4   10
[5,]    5   11
[6,]    6   12

Similarly, we can row-bind – rbind() – the two vectors:

vec1 <- c(1, 2, 3, 4, 5, 6)

vec2 <- c(7, 8, 9, 10, 11, 12)

example_mat4 <- rbind(vec1, vec2)

example_mat4
     [,1] [,2] [,3] [,4] [,5] [,6]
vec1    1    2    3    4    5    6
vec2    7    8    9   10   11   12

Data Structures - Data frames

Data frames are two-dimensional table objects, just like matrices. Most data you will analyze in R will be in this form.

You can create data frames from vectors just like cbind() using data.frame():

vec1 <- c(1, 2, 3, 4, 5, 6)

vec2 <- c(7, 8, 9, 10, 11, 12)

example_df1 <- data.frame(vec1, vec2)

example_df1

However, data frames are always column-bound vectors. In a data frame, everything within a column has to be of the same data type. But you can mix data types between columns:

vec1 <- c(1, 2, 3, 4, 5, 6)

vec2 <- c(7, 8, 9, 10, 11, 12)

vec3 <-
  c(
    "First Row",
    "Second Row",
    "Third Row",
    "Fourth Row",
    "Fifth Row",
    "Sixth Row"
  )

example_df2 <- data.frame(vec1, vec2, vec3)

example_df2

You can also name your columns/variables. Either when creating your data frame:

vec1 <- c(1, 2, 3, 4, 5, 6)

vec2 <- c(7, 8, 9, 10, 11, 12)

vec3 <-
  c(
    "First Row",
    "Second Row",
    "Third Row",
    "Fourth Row",
    "Fifth Row",
    "Sixth Row"
  )

example_df3 <- data.frame(
  variable_1to6 = vec1,
  variable_7to12 = vec2,
  variable_rows = vec3
)

example_df3

Or by renaming an existing data frame.

vec1 <- c(1, 2, 3, 4, 5, 6)

vec2 <- c(7, 8, 9, 10, 11, 12)

vec3 <-
  c(
    "First Row",
    "Second Row",
    "Third Row",
    "Fourth Row",
    "Fifth Row",
    "Sixth Row"
  )

example_df3 <- data.frame(vec1, vec2, vec3)


# Rename the variables of an existing data frame

names(example_df3) <- c("variable.1", "variable.2", "variable.3")

example_df3
vec1 <- c(1, 2, 3, 4, 5, 6)

vec2 <- c(7, 8, 9, 10, 11, 12)

vec3 <-
  c(
    "First Row",
    "Second Row",
    "Third Row",
    "Fourth Row",
    "Fifth Row",
    "Sixth Row"
  )

example_df3 <- data.frame(vec1, vec2, vec3)

names(example_df3) <- c("variable.1", "variable.2", "variable.3")

We can also add a new variable to an existing data frame. We simply create a data frame which consists of a data frame and a vector:

example_df4 <-
  data.frame(example_df3, 
             variable_4 = c(90, 91, 92, 93, 94, 95))

example_df4

Data Structures - Arrays

These are like matrices, except that they are typically three-dimensional. You’re not going to see many of these, but we’ll introduce them for completeness. Here is an illustration of what a three-dimensional array could ook like:

You can think of 10 3 x 5 bingo cards, that all display spaces 1 through 15 for example, as an array. If I were to display that in R, I would use the array function to write:

bingo_array <- array(seq(1, 15, 1), 
                     dim = c(3, 5, 10))

bingo_array

The general syntax for this function is array(values you want to array, dim = (row, column, height)).

Data Structures - Lists

List objects can contain a series of the other objects we just learned about. A single list can contain a value, a vector, a matrix, AND a dataframe - or many of each!

How do I make a list?

Use the list() function!

# create a vector
example_vec <- c(1, 2, 3, 4, 5, 6, 7, 8)

# create a matrix
example_mat <- matrix(c(1, 2, 3, 4, 5, 6),
                      nrow = 3,
                      ncol = 2)

# create an array
example_array <- array(seq(1, 15, 1), dim = c(3, 5, 10))

example_vec3 <- c(1, 2, 3, 4)


## Store all objects in a list

example_list <- list(example_vec, example_mat, example_array)

example_list

Selecting elements in a vector, matrix or data.frame

Sometimes we want to select single or multiple data entries from our objects. We can do this by selecting elements via [].

Let’s first do it with a vector. Remember our country_code vector?

country_code <- c("DE", "FR", "NL", "US", "UK")

country_code
[1] "DE" "FR" "NL" "US" "UK"
country_code <- c("DE", "FR", "NL", "US", "UK")

Let’s say we only want to select the “US”. We can achieve this by accessing the value via its position in the vector:

country_code[4]
[1] "US"

Now we want to select all values but the “US”:

country_code[-4]
[1] "DE" "FR" "NL" "UK"

You can pass multiple indexes as a vector:

country_code[c(1, 2, 3)]
[1] "DE" "FR" "NL"

1:3 generates the vector c(1, 2, 3) a bit quicker.

country_code[1:3]
[1] "DE" "FR" "NL"

If we want the values “DE”, “FR”, and “US”, a sequence does not really help. But we can put a vector with a combination of a sequence and some other values in the square brackets:

country_code[c(1:2, 4)]
[1] "DE" "FR" "US"

Selecting items in two-dimensional objects

We can access values of a matrix similarly. However, we need to think of one additional dimension.

example_mat <- matrix(c(1, 2, 3, 4, 5, 6),
                      nrow = 3,
                      ncol = 2)

example_mat
     [,1] [,2]
[1,]    1    4
[2,]    2    5
[3,]    3    6

Generally, we type object[row, column] to access specific rows and columns. To see how this works, let’s have a look at our example_mat:

Now we want to access the value 6. It’s in the third row and the second column.

example_mat[3, 2]
[1] 6

We could also select an entire column (and use it like a vector).

example_mat[, 2]
[1] 4 5 6

By accessing values with the [] square brackets, we could also replace values. Let’s say we want to recode the entire first column in example_mat3 to 99:

example_mat[, 1] <- 99

example_mat
     [,1] [,2]
[1,]   99    4
[2,]   99    5
[3,]   99    6
example_mat <- matrix(c(1, 2, 3, 4, 5, 6),
                      nrow = 3,
                      ncol = 2)

example_mat[, 1] <- 99
# And we want to recode the first and the third value in the second column
# to 91 and 100

example_mat[c(1, 3), 2] <- c(91, 100)

example_mat
     [,1] [,2]
[1,]   99   91
[2,]   99    5
[3,]   99  100

Selection with conditions

This is a good start to select and recode data in an object. However, it might be a bit exhausting (maybe even impossible) to always look up the exact position in the object.

Luckily, R let’s us also select elements based on conditions. Instead of the position we put a condition in the [] square brackets.

  • For this we can use several conditions:
    • Is equal to: ==
    • Is not: !=
    • Is smaller than: <
    • Is greater than: >
    • Is smaller or equal to: <=
    • Is greater or equal to: >=
  • Conditions can be combined with and and/or or statements
    • AND: &
    • OR: |

So how do conditions work? Let’s create a matrix to work with

vec1 <- c(1, 2, 3, 4, 5, 6)

vec2 <- c(7, 8, 9, 10, 11, 12)

# And now column-bind (cbind()) the two vectors.

example_mat <- cbind(vec1, vec2)

example_mat
     vec1 vec2
[1,]    1    7
[2,]    2    8
[3,]    3    9
[4,]    4   10
[5,]    5   11
[6,]    6   12
vec1 <- c(1, 2, 3, 4, 5, 6)

vec2 <- c(7, 8, 9, 10, 11, 12)

# And now column-bind (cbind()) the two vectors.

example_mat <- cbind(vec1, vec2)
example_mat > 9 # This returns TRUE or FALSE for each value in the object.
      vec1  vec2
[1,] FALSE FALSE
[2,] FALSE FALSE
[3,] FALSE FALSE
[4,] FALSE  TRUE
[5,] FALSE  TRUE
[6,] FALSE  TRUE

Now if we put this condition in square brackets we get the values for which the condition is true.

example_mat[example_mat > 9]
[1] 10 11 12

Working with data.frames

Working with data frames is similar to working with matrices and vectors.

Loading and manipulating data

Usually (and especially for this class) we want to work with existing datasets. R knows and can load most of the standard formats of datasets, like .csv, .xlsx (Excel), .dta (Stata), .sav (SPSS) and many more.

So far we only used R’s base functions. In order to use some more sophisticated or special R functions, we need to load libraries or packages first. Think of these libraries as extra apps that you can load on your smartphones to extend its functionality.

Right now, we want to load the dataset. In order to use the standard but foreign datasets we need the foreign package.

First, we want to have a look at what the package can do.

packageDescription("foreign")
Package: foreign
Priority: recommended
Version: 0.8-81
Date: 2020-12-22
Title: Read Data Stored by 'Minitab', 'S', 'SAS', 'SPSS', 'Stata', 'Systat', 'Weka', 'dBase', ...
Depends: R (>= 4.0.0)
Imports: methods, utils, stats
Authors@R: c( person("R Core Team", email = "R-core@R-project.org", role = c("aut", "cph", "cre")),
           person("Roger", "Bivand", role = c("ctb", "cph")), person(c("Vincent", "J."), "Carey", role
           = c("ctb", "cph")), person("Saikat", "DebRoy", role = c("ctb", "cph")), person("Stephen",
           "Eglen", role = c("ctb", "cph")), person("Rajarshi", "Guha", role = c("ctb", "cph")),
           person("Swetlana", "Herbrandt", role = "ctb"), person("Nicholas", "Lewin-Koh", role =
           c("ctb", "cph")), person("Mark", "Myatt", role = c("ctb", "cph")), person("Michael",
           "Nelson", role = "ctb"), person("Ben", "Pfaff", role = "ctb"), person("Brian", "Quistorff",
           role = "ctb"), person("Frank", "Warmerdam", role = c("ctb", "cph")), person("Stephen",
           "Weigand", role = c("ctb", "cph")), person("Free Software Foundation, Inc.", role = "cph"))
Contact: see 'MailingList'
Copyright: see file COPYRIGHTS
Description: Reading and writing data stored by some versions of 'Epi Info', 'Minitab', 'S', 'SAS',
           'SPSS', 'Stata', 'Systat', 'Weka', and for reading and writing some 'dBase' files.
ByteCompile: yes
Biarch: yes
License: GPL (>= 2)
BugReports: https://bugs.r-project.org
MailingList: R-help@r-project.org
URL: https://svn.r-project.org/R-packages/trunk/foreign/
NeedsCompilation: yes
Packaged: 2020-12-22 13:59:32 UTC; hornik
Author: R Core Team [aut, cph, cre], Roger Bivand [ctb, cph], Vincent J. Carey [ctb, cph], Saikat DebRoy
           [ctb, cph], Stephen Eglen [ctb, cph], Rajarshi Guha [ctb, cph], Swetlana Herbrandt [ctb],
           Nicholas Lewin-Koh [ctb, cph], Mark Myatt [ctb, cph], Michael Nelson [ctb], Ben Pfaff [ctb],
           Brian Quistorff [ctb], Frank Warmerdam [ctb, cph], Stephen Weigand [ctb, cph], Free Software
           Foundation, Inc. [cph]
Maintainer: R Core Team <R-core@R-project.org>
Repository: CRAN
Date/Publication: 2020-12-22 14:59:20 UTC
Built: R 4.1.2; x86_64-apple-darwin17.0; 2021-11-01 20:59:13 UTC; unix

-- File: /Library/Frameworks/R.framework/Versions/4.1/Resources/library/foreign/Meta/package.rds 
# Ok this seems to be useful. So let's load the package to use it.
library(foreign)

You will often come across datasets which are stored as Stata data files. Those files have the extension .dta.

Right now, we want to load the data set called weather_data_germany_2021.dta which is already stored the raw_data folder in our directory:

weather_data <- read.dta("raw_data/weather_data_germany_2021.dta")

The data contains yearly temperature averages of German cities as well as their geographical location (longitude and latitude). It comes from the “Deutscher Wetterdienst” and you can find it here. Now that we have loaded the data, we can have a look at it.

With head()we can look at the first six rows of the data set:

head(weather_data)

But we can also look at the entire data set:

weather_data

If we only want to look at the variable names, we can use names():

names(weather_data)
[1] "city"      "longitude" "latitude"  "mean_temp"

Now we can use our selecting abilities on a data frame. As before we can select elements via their numeric position:

weather_data[1, 2] # first row, second column
[1] 9.387966
weather_data[1:3, 1] # rows 1-3, first column
[1] "Wacken"             "Hasenkrug-Hardebek" "Muskau, Bad"       

Additionally, as columns usually have names in data frames, we can use the column names to select values in two ways.

First, we can put the column name in square brackets instead of a column number:

weather_data[1, "city"]
[1] "Wacken"
weather_data[, "mean_temp"]

We can also look at two variables at once:

weather_data[, c("city", "mean_temp")]

Second, we can also select an entire column by using the $ operator with the column name: data.frame_name$column_name. Just like this:

weather_data$mean_temp
  [1]  9.48  9.35  9.29  8.13 10.54  3.61 10.31  8.98  9.04 11.17  9.63  9.83  7.52  9.27  8.49  8.98  9.46  9.54
 [19]  8.41 10.01  8.95  9.88  8.89  9.43  8.94  9.81  9.92  8.75  7.13  8.87  9.77  9.53  9.59 10.22  9.67  9.41
 [37] 10.16 10.29  6.65  7.47  9.44 10.13  8.23  8.51  9.69 10.45  8.37  6.50  9.45  9.73  9.66  9.52 10.67  7.33
 [55]  9.33  5.29 10.02  5.38  8.26 10.70  9.17  8.75  7.00  9.12  9.79  7.21  8.53  8.82  9.03  7.41  9.77  9.54
 [73]  8.29  9.85  8.51  9.88  8.66  8.61  8.39  7.92 10.21  9.66  9.80  9.95 10.15 10.23  8.61  9.43 10.24  9.95
 [91] 10.40  9.42  8.28  7.52  9.23  8.26  8.42  9.76 10.11  9.13  9.71  9.53  9.59 10.00  9.16  5.85  9.95 10.75
[109]  6.63 10.58  9.27  9.70  9.56 10.49  5.75  9.31  9.07  9.76  8.56  9.71  9.92  7.74  9.28  9.69  8.34  9.74
[127]  7.11  8.18  8.84  7.94  9.64 10.11 10.78  9.43  7.91  8.91 10.98  9.33  7.47  9.31 10.35  8.95  8.93  7.54
[145]  9.68  8.36  9.06  9.57  8.85  9.48  9.62  9.22  9.90  9.42  7.92 10.31  6.77  7.28  9.63  9.43  8.65  9.43
[163]  8.69 10.52  8.49 10.15  9.69  8.77  9.74  9.66  8.57  8.81  9.18  8.16 10.31  7.02  9.27  9.28  8.89  8.93
[181]  9.13  7.56  9.30  9.04  8.80  9.92  8.24  7.94  9.81  8.68  8.66 10.37  9.05  9.78  9.69  8.56  8.46  8.79
[199]  9.05  7.60  8.40  8.41  9.54  9.61  8.75  8.85  9.24  8.12  9.36  9.43  7.77  9.38  9.34  9.73  9.17  6.18
[217]  9.44  8.78  7.20  8.39  9.78  9.77 10.19  9.92  9.47  8.95 10.14  8.90  9.74  7.79  8.69  9.30  8.30  9.48
[235]  7.76  8.62 10.52  9.65  9.23  8.77 10.06  9.34  8.72  8.60 10.85 10.66 10.59  9.05  9.61  8.06  7.25  8.02
[253]  3.78 10.64  9.04  8.98  9.68  9.81  8.45  9.53  9.92  8.45  9.18  9.77  9.70  9.81 10.12  7.78  9.90  8.50
[271]  9.48  9.14 10.40  9.84 10.16  9.07 10.85  8.63 -4.05  8.87 10.20  9.15  9.13  8.87  7.90  9.57  7.11  8.62
[289] 10.00  9.64  8.95  9.58  9.81  8.58  9.98  8.82  9.59  9.09 10.02  9.33 10.24 10.58 10.32  9.40  8.22 10.25
[307]  6.11  7.44  6.39  6.91  8.16  9.56  8.97  9.35  9.49  9.38  8.36 10.33  7.57  9.57  9.48  8.15 10.16  8.52
[325]  8.18  5.74 10.84 10.42  9.97 10.22  9.84  9.66 10.87 10.99  9.69  8.56  8.29  8.23  9.42  7.15  8.72  9.16
[343]  8.69  6.83  9.68  8.77  9.22  8.94  8.16  9.10 10.01  9.39  9.17  9.53 10.55 11.37  9.92  8.26  9.50  8.62
[361]  8.63  6.49  9.89  7.87  8.62  8.90  9.56  9.66  8.68  8.90 10.06  9.50  9.83  9.52  6.90  9.35  5.09  9.90
[379]  9.83  8.91 10.22  8.67  9.80 10.12  8.65  9.54  8.98  8.75  9.30  3.81  8.71  9.13  8.26 10.88  8.47  9.13
[397]  9.61  8.49  9.36  9.71  8.45 10.23  6.90  9.29  7.41  9.57  8.02 10.48  9.18  8.68  9.88  9.50  9.87  9.93
[415]  7.37  7.96  9.16  9.66  9.25  8.57  9.98  9.34  7.59  8.37  9.23  9.84  7.94  9.44  8.87  9.42 10.13  8.70
[433]  9.44  9.40  8.26  8.81  8.91  9.76 10.07  8.02 10.76  8.91 10.61  9.32  9.19  9.21  9.31  8.62  9.04  9.35
[451]  8.75  9.96  9.75 10.06  9.71  7.16  9.79  8.78  9.90 10.52  8.14  9.68 10.03  8.50 10.33  7.80  8.30 10.05
[469]  8.53  9.47  8.70  7.76

Columns from data frames are essentially vectors. We can use all the operations and functions we can use for vectors (depending on their class.)

weather_data$mean_temp[1] # For example, we can select an element of the vector
[1] 9.48

What if we want to add a new variable? Let’s create a variable named “young”.

weather_data$cold <- 0

# What does this do?

weather_data$cold
  [1] 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
 [57] 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
[113] 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
[169] 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
[225] 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
[281] 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
[337] 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
[393] 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
[449] 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0

Now, we want to recode “young” to 1 for people who are younger than 25.

Calculating Measures of Central Tendency and Variability

Let’s look at the Measures of Central Tendency and Variability from the lecture (starting at slide 16).

Consider the following vector:

example_vec <- c(1, 2, 3, 4, 5)

How could we calculate the mean of example_vec?

We could simply calculate it “by hand”:

(1 + 2 + 3 + 4 + 5) / 5
[1] 3

But this is not very useful if we look at an actual vector in our data frame, e.g., mean temperature:

weather_data$mean_temp
  [1]  9.48  9.35  9.29  8.13 10.54  3.61 10.31  8.98  9.04 11.17  9.63  9.83  7.52  9.27  8.49  8.98  9.46  9.54
 [19]  8.41 10.01  8.95  9.88  8.89  9.43  8.94  9.81  9.92  8.75  7.13  8.87  9.77  9.53  9.59 10.22  9.67  9.41
 [37] 10.16 10.29  6.65  7.47  9.44 10.13  8.23  8.51  9.69 10.45  8.37  6.50  9.45  9.73  9.66  9.52 10.67  7.33
 [55]  9.33  5.29 10.02  5.38  8.26 10.70  9.17  8.75  7.00  9.12  9.79  7.21  8.53  8.82  9.03  7.41  9.77  9.54
 [73]  8.29  9.85  8.51  9.88  8.66  8.61  8.39  7.92 10.21  9.66  9.80  9.95 10.15 10.23  8.61  9.43 10.24  9.95
 [91] 10.40  9.42  8.28  7.52  9.23  8.26  8.42  9.76 10.11  9.13  9.71  9.53  9.59 10.00  9.16  5.85  9.95 10.75
[109]  6.63 10.58  9.27  9.70  9.56 10.49  5.75  9.31  9.07  9.76  8.56  9.71  9.92  7.74  9.28  9.69  8.34  9.74
[127]  7.11  8.18  8.84  7.94  9.64 10.11 10.78  9.43  7.91  8.91 10.98  9.33  7.47  9.31 10.35  8.95  8.93  7.54
[145]  9.68  8.36  9.06  9.57  8.85  9.48  9.62  9.22  9.90  9.42  7.92 10.31  6.77  7.28  9.63  9.43  8.65  9.43
[163]  8.69 10.52  8.49 10.15  9.69  8.77  9.74  9.66  8.57  8.81  9.18  8.16 10.31  7.02  9.27  9.28  8.89  8.93
[181]  9.13  7.56  9.30  9.04  8.80  9.92  8.24  7.94  9.81  8.68  8.66 10.37  9.05  9.78  9.69  8.56  8.46  8.79
[199]  9.05  7.60  8.40  8.41  9.54  9.61  8.75  8.85  9.24  8.12  9.36  9.43  7.77  9.38  9.34  9.73  9.17  6.18
[217]  9.44  8.78  7.20  8.39  9.78  9.77 10.19  9.92  9.47  8.95 10.14  8.90  9.74  7.79  8.69  9.30  8.30  9.48
[235]  7.76  8.62 10.52  9.65  9.23  8.77 10.06  9.34  8.72  8.60 10.85 10.66 10.59  9.05  9.61  8.06  7.25  8.02
[253]  3.78 10.64  9.04  8.98  9.68  9.81  8.45  9.53  9.92  8.45  9.18  9.77  9.70  9.81 10.12  7.78  9.90  8.50
[271]  9.48  9.14 10.40  9.84 10.16  9.07 10.85  8.63 -4.05  8.87 10.20  9.15  9.13  8.87  7.90  9.57  7.11  8.62
[289] 10.00  9.64  8.95  9.58  9.81  8.58  9.98  8.82  9.59  9.09 10.02  9.33 10.24 10.58 10.32  9.40  8.22 10.25
[307]  6.11  7.44  6.39  6.91  8.16  9.56  8.97  9.35  9.49  9.38  8.36 10.33  7.57  9.57  9.48  8.15 10.16  8.52
[325]  8.18  5.74 10.84 10.42  9.97 10.22  9.84  9.66 10.87 10.99  9.69  8.56  8.29  8.23  9.42  7.15  8.72  9.16
[343]  8.69  6.83  9.68  8.77  9.22  8.94  8.16  9.10 10.01  9.39  9.17  9.53 10.55 11.37  9.92  8.26  9.50  8.62
[361]  8.63  6.49  9.89  7.87  8.62  8.90  9.56  9.66  8.68  8.90 10.06  9.50  9.83  9.52  6.90  9.35  5.09  9.90
[379]  9.83  8.91 10.22  8.67  9.80 10.12  8.65  9.54  8.98  8.75  9.30  3.81  8.71  9.13  8.26 10.88  8.47  9.13
[397]  9.61  8.49  9.36  9.71  8.45 10.23  6.90  9.29  7.41  9.57  8.02 10.48  9.18  8.68  9.88  9.50  9.87  9.93
[415]  7.37  7.96  9.16  9.66  9.25  8.57  9.98  9.34  7.59  8.37  9.23  9.84  7.94  9.44  8.87  9.42 10.13  8.70
[433]  9.44  9.40  8.26  8.81  8.91  9.76 10.07  8.02 10.76  8.91 10.61  9.32  9.19  9.21  9.31  8.62  9.04  9.35
[451]  8.75  9.96  9.75 10.06  9.71  7.16  9.79  8.78  9.90 10.52  8.14  9.68 10.03  8.50 10.33  7.80  8.30 10.05
[469]  8.53  9.47  8.70  7.76

Typing up all the entries individually would take a lot of time. We could use two functions that we already have seen, sum and length.

sum(weather_data$mean_temp) / length(weather_data$mean_temp)
[1] 9.037903

Fortunately, R provides a much easier way to calculate a mean:

mean(weather_data$mean_temp) # That was easy.
[1] 9.037903

But be sure that your vector is numeric. Could you calculate the mean of city?

weather_data$city

Let’s try to calculate the mean.

mean(weather_data$city)
Warning: argument is not numeric or logical: returning NA
[1] NA

It does not work! And even by hand we could not calculate the mean of character valued vectors.

Here is an overview over functions for measures of centrality and variability:

  • Mean: mean()
  • Median: median()
  • Variance: var()
  • Standard Deviation: sd()
  • Range: range()
  • Inter-quartile range: IQR()

You can try them out here:

# Median

median(weather_data$mean_temp)
[1] 9.28
# Variance

var(weather_data$mean_temp)
[1] 1.566767
# Standard deviation

sd(weather_data$mean_temp)
[1] 1.251706
# Range

range(weather_data$mean_temp)
[1] -4.05 11.37
# Inter Quartile Range (IQR)

IQR(weather_data$mean_temp)
[1] 1.21

Unfortunately, there is no direct function to get the mode. The solutions you will find online are all a bit advanced. So the easiest solution is to look for the mode using a frequency table.

table(weather_data$cold)

  0   1 
409  63 

The table() function shows you how often each value is in the vector. You can now identify the most frequent value.

Plotting data

Let’s have a short look at our data again. Remember: head() shows you the first six entries of your data. It is very useful to get a look at the data structure when you have a lot of rows in your dataset.

Plots for bivariate distributions

Scatterplots

Now we can create a simple scatterplot:

plot(
  x = weather_data$longitude,
  y = weather_data$mean_temp
)

To get a nicer plot, we can adjust many things. We suggest to always explicitly make those adjustments in the same order.

plot(
  x = weather_data$longitude,
  y = weather_data$mean_temp,
  type = "p", # This explicitly says that we want points. You could also try "l".
  main = "Mean temperatures of German cities", # This adds a title to the plot
  xlab = "Longitude (West - East)", # This labels the x-axis.
  ylab = "Mean Temperature in 2021", # What does this do then?
  las = 1, # This affects the tick labels of the y-axis.
  pch = 19, # Here we choose what symbols we want to plot.
  col = "black", # What color should the symbols have?
  frame = F # No box around the plot.
)

Adding Color to Plots with Viridis

We can also adjust the colors. Let’s highlight Mannheim!

Pro Tip: To color up your data visualizations, use the viridis-package.

Viridis colors make it easier to read by those with colorblindness and print well in greyscale. You probably don’t want to have plots like this:

We first need a vector that gives us the right colors with respect to the city variable.

library(viridis)
Loading required package: viridisLite
# we need two colors, this is how we get them:
two_colors <- viridis(2)

two_colors # these are so-called HEX color codes
[1] "#440154FF" "#FDE725FF"
# we use the first color for males and the second for females
mannheim_color <- ifelse(weather_data$city == "Mannheim", two_colors[1], two_colors[2])

# let's have a look:
table(mannheim_color) 
mannheim_color
#440154FF #FDE725FF 
        1       471 

Now we can use this vector to specify the color respective to Mannheim:

plot(
  x = weather_data$longitude,
  y = weather_data$mean_temp,
  type = "p", # This explicitly says that we want points. You could also try "l".
  main = "Mean temperatures of German cities", # This adds a title to the plot
  xlab = "Longitude (West - East)", # This labels the x-axis.
  ylab = "Mean Temperature in 2021", # What does this do then?
  las = 1, # This affects the tick labels of the y-axis.
  pch = 19, # Here we choose what symbols we want to plot.
  col = mannheim_color, # Instead of just black we now use the color vector.
  frame = F # No frame around the plot.
)

Now that we use different colors, we also need a legend to know which color is which.

plot(
  x = weather_data$longitude,
  y = weather_data$mean_temp,
  type = "p", # This explicitly says that we want points. You could also try "l".
  main = "Mean temperatures of German cities", # This adds a title to the plot
  xlab = "Longitude (West - East)", # This labels the x-axis.
  ylab = "Mean Temperature in 2021", # What does this do then?
  las = 1, # This affects the tick labels of the y-axis.
  pch = 19, # Here we choose what symbols we want to plot.
  col = mannheim_color, # Instead of just black we now use the color vector.
  frame = F # No frame around the plot.
)
legend(
  "bottomleft", # Locate the legend in the topleft corner.
  legend = c("Mannheim", "other"), # Give it labels.
  pch = 19, # Specify symbols as in the scatterplot.
  col = two_colors, # Specify colors.
  bty = "n" # No box around the legend.
)

plot(
  x = weather_data$longitude,
  y = weather_data$mean_temp,
  type = "p", # This explicitly says that we want points. You could also try "l".
  main = "Mean temperatures of German cities", # This adds a title to the plot
  xlab = "Longitude (West - East)", # This labels the x-axis.
  ylab = "Mean Temperature in 2021", # What does this do then?
  las = 1, # This affects the tick labels of the y-axis.
  pch = 19, # Here we choose what symbols we want to plot.
  col = mannheim_color, # Instead of just black we now use the color vector.
  frame = F # No frame around the plot.
)
text(
  x = weather_data$longitude[weather_data$city == "Mannheim"],
  y = weather_data$mean_temp[weather_data$city == "Mannheim"],
  labels = "Mannheim",
  pos = 4
)

Plots for univariate distributions

Histograms

Now we want to visualize mean temperature with a histogram. This is how you get a standard histogram:

hist(x = weather_data$mean_temp) # That's intuitive, but does not look too great

Again, we can adjust many things to make it nicer.

hist(
  x = weather_data$mean_temp, # For a histogram we only specify x.
  breaks = 50, # specify the number of bins
  main = "A Histogram",
  xlab = "Mean temperature",
  ylab = "Number of observations",
  las = 1, # shift the y-axis labels 
  col = viridis(1), # One color only (first color from viridis)
  border = "white" # That's the color of the bin borders.
)

Density Plots

We can also create density plots.

plot(
  density(weather_data$mean_temp), # density() takes care of x, y and type.
  main = "A Simple Density Plot",
  xlab = "Mean temperature",
  ylab = "", # The y-axis is not really meaningful here.
  col = viridis(1),
  lwd = 2, # Control the width of the line
  frame = F,
  yaxt = "n" # Remove the y-axis.
)

And we can also fill the are underneath the curve:

plot(
  density(weather_data$mean_temp), # density() takes care of x, y and type.
  main = "A Simple Density Plot",
  xlab = "Mean temperature",
  ylab = "", # The y-axis is not really meaningful here.
  col = viridis(1),
  lwd = 2, # Control the width of the line
  frame = F,
  yaxt = "n" # Remove the y-axis.
)

polygon(density(weather_data$mean_temp), 
        col = viridis(1, alpha = 0.5) # same color but 50% transparent
        )

…and Boxplots

boxplot(
  x = weather_data$mean_temp, # As for histograms we only specify x.
  main = "Boxplot of Mean temperature in degree Celsius",
  ylab = "Mean temperature in degree Celsius",
  las = 1,
  col = plasma(1),
  frame = F
)

Or a horizontal boxplot.

boxplot(
  x = weather_data$mean_temp,
  horizontal = T, # With horizontal = T we rotate the boxplot.
  main = "Horizontal Boxplot of Mean temperature in degree Celsius",
  xlab = "Mean temperature in degree Celsius",
  las = 1,
  frame = F
)

You learned in the lecture that boxplots have some disadvantages.

Violin plots are a very nice alternative!

This is how you get them:

library(vioplot)

vioplot(
  x = weather_data$mean_temp,
  horizontal = T, # With horizontal = T we rotate the boxplot.
  main = "Horizontal Violinplot of Mean temperature in degree Celsius",
  xaxt = "n",
  xlab = "Mean temperature in degree Celsius",
  bty = "n",
  axes = FALSE,
  names = "",
  border = NA
)

Your turn: Exercises!

This has been a lot but now it’s finally your turn! We have a series of exercises for you to try out the stuff you just learned.

Pro tip: Copy the lines of code that worked for something similar. Then, adjust the code according to your problem. That’s how coding works most of the time!

Exercise I: Creating objects

Create three objects:

1. `my_lucky_number` should contain your lucky number.
2. `my_firstname` should contain your firstname.
3. `my_lastname` should contain your lastname.

After you created the objects, call them separately. Don’t forget to add comments to your code.

Exercise II: Selecting and recoding elements

  1. Create two vectors vec1 and vec2.

    • vec1 should contain 1, 56, 23, 89, -3 and 5 (in that order).
    • vec2 contains 24, 78, 32, 27, 8 and 1.
  2. Now select elements of vec1 that are greater than 5 or smaller than 0.

  3. Next set vec1 to zero if vec2 is greater than 30 and smaller or equal to 32.

Please solve all three steps in the next code chunk.

Exercise III: Manipulating data

Now we will work with the weather_data data set. It is already loaded for you and you can use it right away.

  1. Show the variable age if it is over 60.

  2. Generate a new variable and call it hot that is zero for mean temperature < 10 and 1 for mean temperature > 10 degree Celsius.

  3. Have a look at your data set.

Please solve all three steps in the next code chunk.

Exercise IV: Subsetting

Can you find the hottest and coldest city in Germany 2021?

Hint: The functions min() and max() help you to find the minimum and maximum values of a vector or variable. Combine that with your newly learned subsetting skills and you’ll find the answer.

Exercise V: Measures of central tendency

We will continue working with the weather data set

  1. Calculate the mean value of age and save the result as latitude.
  1. Calculate the variance of age and save the result as latitude.
  1. Calculate the standard deviation of age and save the result as latitude.

Exercise VI: Plotting

  1. Make a histogram of the latitude variable.
  1. Make the plot nice looking (Name the axes, main title, colors…)

Recap

What we learned in this session:

  1. How to work with R and GitHub.
  2. Assigning objects in R.
  3. Different data structures in R.
  4. How to get to single elements within data structures.
  5. Working with data frames.
  6. How to load a data set into R.
  7. How to make nice looking plots in R.

What you will do in your homework.

The first lab session and this script should equip you with all the tools (and lines of code) to tackle the first homework assignment.

Copy the lines of code that worked for something similar. Then, adjust the code according to your problem.

Substantially, in your homework you will inspect a data set on US presidential elections. You will calculate some measures of central tendency and variability. Finally, you will produce some nice plots.

It is best to get started with your homework as soon as possible (after it was handed out on Tuesday).

Try to write the R Code first. We will provide you a .Rmd template to hand in your results.

In order to pass the homework assignment you need to tackle ALL problems of a problem set. For a pass you also need to get most of the problems right (or at least show us that you tried everything to get it right.)

Closing remarks.

If you have any questions concerning the lecture or the tutorial please post them to the ILIAS forum or on Slack. We will answer them on a regular basis.

Do not hesitate to come to the office hours!

And always remember if you have a question, it is never a stupid question. In fact most of your fellow students probably have the same or a similar question. By asking it, everyone in this class will profit.

LS0tCnRpdGxlOiAiUU0gMjAyMiBXZWVrIDE6PGJyPkdldHRpbmcgU3RhcnRlZCB3aXRoIFIiCmF1dGhvcjogIk9saXZlciBSaXR0bWFubjxicj5Eb21hbnRhcyBVbmR6xJduYXM8YnI+TGlvbiBCZWhyZW5zPGJyPiIKZGF0ZTogIlNlcHRlbWJlciA3IHwgOCB8IDksIDIwMjIiCm91dHB1dDoKICBodG1sX2RvY3VtZW50OgogICAgdG9jOiB0cnVlCiAgICB0b2NfZmxvYXQ6IHRydWUKICAgIGNzczogY3NzL2xhYi5jc3MKICBwZGZfZG9jdW1lbnQ6CiAgICB0b2M6IHllcwogIGh0bWxfbm90ZWJvb2s6CiAgICB0b2M6IHRydWUKICAgIHRvY19mbG9hdDogdHJ1ZQogICAgY3NzOiBjc3MvbGFiLmNzcwotLS0KCiMjIExlYXJuaW5nIGdvYWxzIG9mIHRoZSBmaXJzdCB3ZWVrCgogIDEuIFdoYXQgYXJlIFIsIFJTdHVkaW8sIGFuZCBHaXQ/CiAgMi4gSG93IHRvIHVzZSAqKlIgYXMgYSBiYXNpYyBjYWxjdWxhdG9yKio/CiAgMy4gV2hhdCBhcmUgKipPYmplY3RzIGluIFIqKj8KICA0LiBTb21ldGhpbmcgYWJvdXQgKipSIERhdGEgc3RydWN0dXJlcyoqCiAgICAgIC0gVmVjdG9ycwogICAgICAtIE1hdHJpY2VzCiAgICAgIC0gRGF0YSBmcmFtZXMKICAgICAgLSBBcnJheXMKICAgICAgLSBMaXN0cwogIDUuICoqU2VsZWN0aW5nIEVsZW1lbnRzKiogaW4gYSB2ZWN0b3IsIG1hdHJpeCBvciBkYXRhIGZyYW1lCiAgNi4gV29ya2luZyB3aXRoICoqZGF0YSBmcmFtZXMqKgogICAgICAtIExvYWRpbmcgZGF0YSAKICAgICAgLSBNYW5pcHVsYXRpbmcgZGF0YQogIDcuIENhbGN1bGF0aW5nICoqTWVhc3VyZXMgb2YgQ2VudHJhbCBUZW5kZW5jeSBhbmQgVmFyaWFiaWxpdHkqKgogIDguICoqUGxvdHRpbmcgZGF0YSoqIGFuZCBzYXZpbmcgcGxvdHMKIAoKCiMjIFdoYXQgYXJlIFIsIFJTdHVkaW8sIGFuZCBHaXQ/CgojIyMgV2hhdCBpcyAqKlIqKj8KCmBSYCBpcyBhIHByb2dyYW1taW5nIGxhbmd1YWdlIGRlc2lnbmVkIHRvIGhlbHAgeW91IHBlcmZvcm0gc3RhdGlzdGljYWwgYW5hbHlzaXMsIGNyZWF0ZSBncmFwaGljcywgYW5kIGxhdGVyIG9uIHdyaXRlIHlvdXIgb3duIHN0YXRpc3RpY2FsIHNvZnR3YXJlLiBgUmAgaXMgYmVjb21pbmcgaW5jcmVhc2luZ2x5IHBvcHVsYXIgYW5kIGtub3dsZWRnZSBvZiBSIHdpbGwgaGVscCB5b3Ugb24gdGhlIGpvYiBtYXJrZXQuIGBSYCBpcyBwcm9iYWJseSB0aGUgbW9zdCB2ZXJzYXRpbGUgc3RhdGlzdGljYWwgdG9vbCBvdXQgdGhlcmUgKGFuZCBpdCdzIGZyZWUgYW5kIG9wZW4tc291cmNlIHNvIHlvdSBjYW4gbGl0ZXJhbGx5IHVzZSBpdCBhbnl3aGVyZSkuIEl0IGlzIGZvciBleGFtcGxlIHVzZWQgaW4gYWxsIGZpZWxkcyBvZiBhY2FkZW1pYSwgZnJvbSBiaW9sb2d5IHRvIGVjb25vbWljcywgYW5kIG91dHNpZGUgYWNhZGVtaWEgaW5jbHVkaW5nCgogLSBXYWxsc3RyZWV0CiAtIFRoZSBFY29ub21pc3QKIC0gW0JCQ10oaHR0cHM6Ly9ibG9nLnJldm9sdXRpb25hbmFseXRpY3MuY29tLzIwMTgvMDYvZnQtYmJjLXVzZXMtci5odG1sKQogLSBHb29nbGUgQW5hbHl0aWNzCiAtIE5ZIFRpbWVzIGdyYXBoaWNzIGRlcGFydG1lbnQKIAogCiMjIyBXaGF0IGlzICoqUlN0dWRpbyoqPwoKUlN0dWRpbyBpcyBhIGdyZWF0IGdyYXBoaWNhbCB1c2VyIGludGVyZmFjZSBmb3IgYFJgLiBJbiByZWNlbnQgeWVhcnMsIGEgZ3Jvd2luZyBudW1iZXIgb2YgZmVhdHVyZXMgaGF2ZSBiZWVuIGFkZGVkIHRvIHRoaXMgZ3JhcGhpY2FsIHVzZXIgaW50ZXJmYWNlLCB3aGljaCBtYWtlcyBpdCB0aGUgcHJlZmVycmVkIGNob2ljZSBmb3IgbGVhcm5pbmcgYFJgLCBlc3BlY2lhbGx5IGFtb25nIGJlZ2lubmVycy4gWW91IGNhbiB0aGluayBhYm91dCBpdCBhcyBgUmAgYmVpbmcgdGhlIGVuZ2luZSBvZiB0aGUgY2FyIGFuZCBSU3R1ZGlvIGJlaW5nIHRoZSBkYXNoYm9hcmQuIAoKIyMjIFdoYXQgYXJlICoqUlN0dWRpbyBQcm9qZWN0cyoqPwoKUlN0dWRpbyBwcm9qZWN0cyBtYWtlIGl0IHN0cmFpZ2h0Zm9yd2FyZCB0byBkaXZpZGUgeW91ciB3b3JrIGludG8gbXVsdGlwbGUgY29udGV4dHMsIGVhY2ggd2l0aCBpdHMgb3duIHdvcmtpbmcgZGlyZWN0b3J5LCB3b3Jrc3BhY2UsIGhpc3RvcnksIGFuZCBzb3VyY2UgZG9jdW1lbnRzLiBBIHByb2plY3QgaXMgYmFzaWNhbGx5IGEgZm9sZGVyIG9uIHlvdXIgY29tcHV0ZXIgdGhhdCBob2xkcyBhbGwgdGhlIGZpbGVzIHJlbGV2YW50IHRvIGEgcGFydGljdWxhciBwaWVjZSBvZiB3b3JrLiBXb3JraW5nIGluIFJTdHVkaW8gUHJvamVjdHMgaGFzIG11bHRpcGxlIGFkdmFudGFnZXM6CgogIC0gT25jZSBhbiBSU3R1ZGlvIFByb2plY3QgaXMgc2V0IHVwLCB5b3UgZG8gbm90IGhhdmUgdG8gd29ycnkgYWJvdXQgeW91ciB3b3JraW5nIGRpcmVjdG9yeSBhbnltb3JlLgogIC0gV2hlbiBvcGVuaW5nIGFuIFJTdHVkaW8gUHJvamVjdCwgYSBuZXcgYFJgIHNlc3Npb24gKHByb2Nlc3MpIGlzIHN0YXJ0ZWQuIFRoaXMgbWFrZXMgc3VyZSB0aGF0IHRoaW5ncyB5b3UgZG8gaW4gZGlmZmVyZW50IHByb2plY3RzIGRvIG5vdCBtZXNzIHVwLgogIC0gWW91IGNhbiBvcGVuIGFuZCB3b3JrIHdpdGggbXVsdGlwbGUgUlN0dWRpbyBwcm9qZWN0cyBhdCB0aGUgc2FtZSB0aW1lLgogIC0gUlN0dWRpbyBwcm9qZWN0cyBjYW4gZWFzaWx5IGJlIGV4cG9ydGVkIHRvIGFuZCBpbXBvcnRlZCBmcm9tIEdpdEh1Yi4KCgojIyMgV2hhdCBhcmUgKipHaXQqKiBhbmQgKipHaXRIdWIqKj8KCkdpdCBpcyBhIHZlcnNpb24gY29udHJvbCBzeXN0ZW0gdGhhdCBtYWtlcyBpdCBlYXN5IHRvIHRyYWNrIGNoYW5nZXMgYW5kIHdvcmsgb24gY29kZSBjb2xsYWJvcmF0aXZlbHkuIEdpdEh1YiBpcyBhIGhvc3Rpbmcgc2VydmljZSBmb3IgYGdpdGAuIFlvdSBjYW4gdGhpbmsgb2YgaXQgYXMgYSBwdWJsaWMgRHJvcGJveCBmb3IgY29kZSBidXQgb24gc3Rlcm9pZHMuIFdpdGggdmVyc2lvbiBjb250cm9sLCB5b3Ugd2lsbCBidWlsZCB5b3VyIHByb2plY3RzIHN0ZXAtYnktc3RlcCwgYmUgYWJsZSB0byBjb21lIGJhY2sgdG8gYW55IHZlcnNpb24gb2YgdGhlIHByb2plY3QsIGFuZCBhY2NvbXBhbnkgZXZlcnl0aGluZyB3aXRoIGh1bWFuLXJlYWRhYmxlIG1lc3NhZ2VzLiAKCkFzIGEgc3R1ZGVudCwgeW91IGV2ZW4gZ2V0IHVubGltaXRlZCBwcml2YXRlIHJlcG9zaXRvcmllcyB3aGljaCB5b3UgY2FuIHVzZSBpZiB5b3UgZG9uJ3QgZmVlbCBsaWtlIHNoYXJpbmcgeW91ciBjb2RlIHdpdGggdGhlIHJlc3Qgb2YgdGhlIHdvcmxkICh5ZXQpLiBXZSB3aWxsIHVzZSBwcml2YXRlIHJlcG9zaXRvcmllcyB0byBkaXN0cmlidXRlIGNvZGUgYW5kIGFzc2lnbm1lbnRzIHRvIHlvdS4gQW5kIHlvdSB3aWxsIHVzZSBpdCB0byBrZWVwIHRyYWNrIG9mIHlvdXIgY29kZSBhbmQgY29sbGFib3JhdGUgaW4gdGVhbXMuIAoKV2l0aCBnaXQsIHdyaXRpbmcgY29kZSBmb3IgYSBwcm9qZWN0IHdpbGwgbG9vayBzb21ld2hhdCBsaWtlIHRoaXM6CgohW10oaW1hZ2VzL2xlZ28tc3RlcHMtY29tbWl0LW1lc3NhZ2VzLnBuZykKCgojIyMgV2hhdCBpcyBhICoqR2l0IFJlcG9zaXRvcnkqKj8gCgpBIEdpdCByZXBvc2l0b3J5IGlzIGEgc3BhY2Ugd2hlcmUgeW91IHN0b3JlIGFuZCBtYW5hZ2UgYSBwcm9qZWN0LiBJdCBjb250YWlucyBhbGwgb2YgeW91ciBwcm9qZWN0J3MgZmlsZXMgYW5kIHN0b3JlcyBlYWNoIGZpbGUncyByZXZpc2lvbiBoaXN0b3J5LiBJdCdzIGNvbW1vbiB0byByZWZlciB0byBhIHJlcG9zaXRvcnkgYXMgYSByZXBvLiAKCldlIHdpbGwgeW91IG9uZSByZXBvc2l0b3J5IGZvciBlYWNoIGxhYiBhbmQgb25lIHJlcG9zaXRvcnkgZm9yIGVhY2ggaG9tZXdvcmsgYXNzaWdubWVudC4gWW91IGNhbiBkaXJlY3RseSBpbXBvcnQgKCJwdWxsIikgcmVwb3NpdG9yaWVzIHZpYSBSU3R1ZGlvIGFuZCBzYXZlIHRoZW0gb24geW91ciBjb21wdXRlci4gSWYgeW91IGNoYW5nZWQgc29tZXRoaW5nIGluIHlvdXIgcHJvamVjdCwgeW91IGNhbiBlYXNpbHkgdXBsb2FkICgicHVzaCIpIHRoZSBuZXcgdmVyc2lvbiB0byBHaXRIdWIuIEdpdEh1YiB3aWxsIGtlZXAgdHJhY2sgb2YgYWxsIGNoYW5nZXMgeW91IG1hZGUgb3ZlciB0aW1lIHdpdGhpbiB5b3VyIHByb2plY3QuCgoKIyMgV29ya2Zsb3cgb3ZlcnZpZXcKCk91ciB3b3JrZmxvdyB3aWxsIGFwcGVhciBhIGJpdCB0cmlja3kgYXQgdGhlIGJlZ2lubmluZyBidXQgd2UgYXJlIHN1cmUgdGhhdCB5b3Ugd2lsbCBoYW5kbGUgaXQgd2l0aCBlYXNlIHZlcnkgc29vbi4gV2UgYXNzdW1lIHRoYXQgYnkgbm93IHlvdSBkb3dubG9hZGVkIGFuZCBpbnN0YWxsZWQgUiBhbmQgUnN0dWRpbyBhbmQgaGF2ZSB5b3VyIHBlcnNvbmFsIEdpdEh1YiBhY2NvdW50LgoKVGhlIGNvdXJzZSBoYXMgaXRzIG93biBwYWdlIG9uIEdpdEh1YiwgeW91IGNhbiBmaW5kIGl0IGhlcmU6IFtodHRwczovL2dpdGh1Yi5jb20vdW5pLW1hbm5oZWltLXFtLTIwMjJdKGh0dHBzOi8vZ2l0aHViLmNvbS91bmktbWFubmhlaW0tcW0tMjAyMikuIFRoaXMgaXMgdGhlIHBsYWNlIHdoZXJlIHlvdSBjYW4gZmluZCBhbGwgcmVsZXZhbnQgbWF0ZXJpYWwgZm9yIHRoZSBsYWIgc2Vzc2lvbnMuIEl0IGlzIGFsc28gdGhlIHBsYWNlIHdoZXJlIHlvdSBkb3dubG9hZCBhbmQgaGFuZCBpbiB5b3VyIGhvbWV3b3JrIGFzc2lnbm1lbnRzLiAKClNvIGhvdyBkb2VzIHRoaXMgd29yaz8KCiMjIyMgR2V0IHRoZSBVUkwgb2YgdGhlIHJlcG8gZm9yIHRoZSBjdXJyZW50IHdlZWsKCkdvIHRvIFtodHRwczovL2dpdGh1Yi5jb20vdW5pLW1hbm5oZWltLXFtLTIwMjJdKGh0dHBzOi8vZ2l0aHViLmNvbS91bmktbWFubmhlaW0tcW0tMjAyMikgYW5kIGNsaWNrIG9uIHRoZSByZXBvc2l0b3J5IGZvciB0aGUgY3VycmVudCB3ZWVrICh0aGlzIHdlZWssIHRoaXMgaXMgY2FsbGVkIGB3ZWVrMDFfaW50cm9kdWN0aW9uYCkuIE5vdywgY2xpY2sgb24gdGhlIGdyZWVuICoqQ2xvbmUgb3IgZG93bmxvYWQqKiBidXR0b24gYW5kIHNlbGVjdCAqKlVzZSBIVFRQUyoqICh0aGlzIG1pZ2h0IGFscmVhZHkgYmUgc2VsZWN0ZWQgYnkgZGVmYXVsdCwgYW5kIGlmIGl0IGlzLCB5b3UnbGwgc2VlIHRoZSB0ZXh0IENsb25lIHdpdGggSFRUUFMgYXMgaW4gdGhlIGltYWdlIGJlbG93KS4gQ2xpY2sgb24gdGhlIGNsaXBib2FyZCBpY29uIHRvIGNvcHkgdGhlIHJlcG8gVVJMLgoKYGBge3IgZWNobz1GQUxTRSwgb3V0LndpZHRoPSI0MCUiLCBmaWcuYWxpZ24gPSAnY2VudGVyJ30Ka25pdHI6OmluY2x1ZGVfZ3JhcGhpY3MoImltYWdlcy9naXRodWJfY2xvbmUucG5nIikKYGBgCgojIyMjIEltcG9ydCB0aGUgcmVwb3NpdG9yeSBpbiBSU3R1ZGlvCgogIDEuIE9wZW4gUlN0dWRpby4KICAyLiBDbGljayBvbiBgRmlsZWAgb24gdGhlIHRvcCBiYXIgYW5kIHNlbGVjdCBgTmV3IFByb2plY3QuLi5gLgoKYGBge3IgZWNobz1GQUxTRSwgb3V0LndpZHRoPSIxMDAlIiwgZmlnLmFsaWduID0gJ2NlbnRlcid9CmtuaXRyOjppbmNsdWRlX2dyYXBoaWNzKCJpbWFnZXMvbmV3X3Byb2plY3QucG5nIikKYGBgCgogIDMuIFNlbGVjdCBgVmVyc2lvbiBDb250cm9sYC4gCiAgNC4gSW4gdGhlIG5leHQgd2luZG93LCBzZWxlY3QgYEdpdGAuCiAgNS4gSW4gdGhlIGZpbmFsIHdpbmRvdywgcGFzdGUgdGhlIHJlcG8gVVJMIHlvdSBncmFiYmVkIGZyb20gR2l0SHViIGluIHRoZSBgUmVwb3NpdG9yeSBVUkxgIHdpbmRvdy4gQ2xpY2sgb24gYEJyb3dzZWAgdG8gc2VsZWN0IHRoZSBmb2xkZXIgb24geW91ciBjb21wdXRlciB3aGVyZSB5b3Ugd2FudCB0byBzdG9yZSB0aGUgcHJvamVjdC4KICA2LiBDbGljayBvbiBgQ3JlYXRlIFByb2plY3RgLgogIAojIyMjIEdldCB3b3JraW5nCiAgNy4gT3BlbiB0aGUgYC5SbWRgIGZpbGUgdGhhdCBpcyBzdG9yZWQgaW4gdGhlIHByb2plY3QgKGluIHdlZWsgMSwgdGhpcyBpcyBjYWxsZWQgYFFNMjAyMl9XZWVrMDEuUm1kYCkuCgoKIyMgVGhlIFJTdHVkaW8gaW50ZXJmYWNlCgpUaGUgUlN0dWRpbyBpbnRlcmZhY2UgaGFzIGZvdXIgcGFuZXM6CgpgYGB7ciwgZWNobz1GQUxTRSwgb3V0LndpZHRoPSIxMDAlIiwgZmlnLmFsaWduID0gJ2NlbnRlcid9CmtuaXRyOjppbmNsdWRlX2dyYXBoaWNzKCJpbWFnZXMvcnN0dWRpb19pbnRlcmZhY2UucG5nIikKYGBgCgogIC0gKipFZGl0b3IqKjogVGhpcyBpcyB3ZXJlIHlvdSB1c3VhbGx5IGNvZGUuIFlvdSBjYW4gZWl0aGVyIHVzZSAuUm1kIChSIE1hcmtkb3duKSBvciAuUiAocGxhaW4gUiBjb2RlKSBmaWxlcy4KICAtICoqQ29uc29sZSoqOiBUaGlzIGlzIHdoZXJlIHRoZSByZXN1bHRzIGFwcGVhciBvbmNlIHlvdSBleGVjdXRlIHlvdXIgUi1jb2RlLiBZb3UgY2FuIGFsc28gZGlyZWN0bHkgdHlwZSBSLWNvZGUgaW50byB0aGUgY29uc29sZSBhbmQgZXhlY3V0ZSBpdC4gSG93ZXZlciwgd2UgY2Fubm90IHNhdmUgdGhpcyBjb2RlIHdoaWNoIGlzIHdoeSB3ZSB1c3VhbGx5IHdvcmsgaW4gdGhlIEVkaXRvci4KICAtICoqRW52aXJvbm1lbnQqKjogSGVyZSB5b3UgaGF2ZSBhbiBvdmVydmlldyBvdmVyIGFsbCB0aGUgb2JqZWN0cyBjdXJyZW50bHkgbG9hZGVkIGluIHlvdXIgZW52aXJvbm1lbnQuIFlvdSB3aWxsIGxlYXJuIG1vcmUgYWJvdXQgb2JqZWN0cyBsYXRlciBpbiB0aGUgY291cnNlLgogIC0gKipGaWxlcywgUGxvdHMsIFBhY2thZ2VzLCBIZWxwLCBWaWV3ZXIqKjogUGxvdHMgYW5kIG90aGVyIHRoaW5ncyB3aWxsIGFwcGVhciBoZXJlLCBkb24ndCB3b3JyeSB0b28gbXVjaCBhYm91dCBpdCBmb3IgdGhlIG1vbWVudC4KCgojIyBSIGFzIGEgYmFzaWMgY2FsY3VsYXRvcgoKRW5vdWdoIHByZXBhcmF0aW9uLCBsZXQncyBmaW5hbGx5IGRpdmUgaW50byBSIQoKUiBjYW4gcGVyZm9ybSBiYXNpYyBtYXRoIG9wZXJhdGlvbnMuIEhlcmUgYXJlIHNvbWUgZXhhbXBsZXM6CgpgYGB7ciBDYWxjdWxhdG9yfQoxICsgMQpgYGAKClNvbWUgbW9yZSBjYWxjdWxhdGlvbnM6CgpgYGB7ciBDYWxjdWxhdG9yMn0KMiAtIDMKCjQgKiA1CgoyXjIKCjQgLyAyCgoyXigxIC8gMikKYGBgCgpJZiB5b3UgcGxhY2UgcGFyZW50aGVzZXMgY29ycmVjdGx5LCBSIGluY29ycG9yYXRlcyB0aGUgb3JkZXIgb2Ygb3BlcmF0aW9ucy4KCmBgYHtyIENhbGN1bGF0b3IzfQooKDIgKyAyKSAqIDIpXjIKYGBgCgpUaGlzIHNob3VsZCBnaXZlIHRoZSBzYW1lIHJlc3VsdCBhcyBiZWZvcmUuCgpgYGB7ciBDYWxjdWxhdG9yNH0KKDQgKiAyKV4yCmBgYAoKCkJ1dCB0aGlzIG9mIGNvdXJzZSBnaXZlcyBhIGRpZmZlcmVudCByZXN1bHQ6CgpgYGB7ciBDYWxjdWxhdG9yNX0KKDIgKyAyICogMileMgpgYGAKICAgIApZb3UgY2FuIGFsc28gdXNlIG90aGVyIG1hdGggZnVuY3Rpb25zIHlvdSBrbm93IGZyb20geW91ciBjYWxjdWxhdG9yOgoKdGhpcyBpcyAkXHNxcnR7Mn0kCgpgYGB7ciBzcXJ0fQpzcXJ0KDIpCmBgYAoKd2hlbiB5b3UgZG8gbm90IHNwZWNpZnkgdGhlIGJhc2UsIFIgdXNlcyB0aGUgbmF0dXJhbCBsb2cgd2l0aCBiYXNlICRlJCwgaS5lLiAkXGxvZ19lKDEwKSQKCmBgYHtyIGxvZzF9CmxvZygxMCkKYGBgCgpidXQgUiBjYW4gYWxzbyB1c2UgYSBkaWZmZXJlbnQgKHZpcnR1YWxseSBhbnkpIGJhc2UsIGUuZy4gJFxsb2dfezEwfSgxMCkkCgpgYGB7ciBsb2cyLCBleGVyY2lzZT1UUlVFfQpsb2coMTAsIGJhc2UgPSAxMCkKYGBgCgpvciB3aXRoIGJhc2UgPSA1LCBpLmUuICRcbG9nXzUoMTApJAoKYGBge3IgbG9nM30KbG9nKDEwLCA1KQpgYGAKCgo+IDxpIGNsYXNzPSJmYSBmYS1ncmFkdWF0aW9uLWNhcCI+PC9pPiAqKlBybyB0aXA6KiogQWx3YXlzIGNsb3NlIHlvdXIgcGFyZW50aGVzZXMhIAoKCiAgLSBJZiB5b3UgZW5jb3VudGVyIGFuIGVycm9yIHdoZW4gcnVubmluZyB5b3VyIGNvZGUsIGl0IGlzIG9mdGVuIGEgbWlzc2luZyBwYXJlbnRoZXNpcywgYnJhY2Ugb3IgYnJhY2tldC4KICAtIFJTdHVkaW8gaGlnaGxpZ2h0cyB5b3VyIHBhaXJlZCBwYXJlbnRoZXNpcy4gVGhpcyBpcyByZWFsbHkgbmljZSBhbmQgaGVscGZ1bCEKCgojIyBNYWtlIHVzZSBvZiBjb21tZW50cwoKSXQgaXMgaGFyZCB0byB1bmRlcnN0YW5kIHB1cmUgY29kZSwgZXNwZWNpYWxseSBmb3Igc29tZW9uZSB3aG8gZGlkIG5vdCB3cml0ZSBpdCAoYW5kIGZ1dHVyZS15b3Ugd2lsbCBhbHNvIGhhdmUgYSBoYXJkIHRpbWUgdG8gdW5kZXJzdGFuZCBpdCkuCgoKPiA8aSBjbGFzcz0iZmEgZmEtZ3JhZHVhdGlvbi1jYXAiPjwvaT4gKipQcm8gdGlwOioqIEFkZCBjb21tZW50cyB0byB5b3VyIGNvZGUsIGRlc2NyaWJpbmcgd2hhdCB5b3UgYXJlIGRvaW5nIGFuZCB3aHkgeW91IGFyZSBkb2luZyBpdC4KCiAKKipXaXRoIGNvbW1lbnRzOioqCgotIE90aGVyIHBlb3BsZSBjYW4gdW5kZXJzdGFuZCB5b3VyIGNvZGUgKGZvciBleGFtcGxlIHVzIHdoZW4gd2UgYXJlIGdvaW5nIHRocm91Z2ggeW91ciBIb21ld29yayBhc3NpZ25tZW50cyBvciB5b3VyIGNsYXNzbWF0ZXMgd2hlbiB5b3UgYXJlIHRhbGtpbmcgYWJvdXQgeW91ciB3b3JrKS4KLSBZb3UgY2FuIHJlbWVtYmVyIHdoYXQgeW91IHdlcmUgZG9pbmcgd2hlbiB5b3UgcmVvcGVuIHlvdXIgY29kZSBhZnRlciB3ZWVrcyAoZS5nLiwgdG8gcHJlcGFyZSB0aGUgZGF0YSBlc3NheSBhdCB0aGUgZW5kIG9mIHRoZSBzZW1lc3RlcikuCgojIyMgU28gaG93IGNhbiBJIGFkZCBjb21tZW50cz8KCi0gQmVnaW4gYSBsaW5lIHdpdGggYSBgI2Agc3ltYm9sLCAKLSBFdmVyeXRoaW5nIG9uIHRoYXQgbGluZSBhZnRlciB0aGUgYCNgIHdpbGwgYmUgY29tbWVudGVkIG91dC4KLSBUaGlzIG1lYW5zIGlmIHlvdSBzZW5kIHRoZSBzY3JpcHQgdG8gdGhlIFIgY29uc29sZSB0aGUgY29uc29sZSB3aWxsIG5vdCBydW4gdGhlc2UgbGluZXMuIAoKYGBge3IgYWRkaXRpb259CiMgdGhpcyBpcyBhIGNvbW1lbnQKCjEgKyAxICMgVGhpcyBsaW5lIHJ1bnMKCiMgMSArIDEgVGhpcyBsaW5lIGRvZXMgbm90IHJ1bgpgYGAKCi0gSW5kZW50IHlvdXIgc2NyaXB0cyAoYm90aCBjb2RlIGFuZCBjb21tZW50cykgdXNpbmcgc3BhY2VzIHNvIHRoYXQgdGhleSBhcmUgcmVhZGFibGUuCi0gVHJ5IHRvIGNvZGUgYWNjb3JkaW5nIHRvIFtHb29nbGUncyBSIFN0eWxlIEd1aWRlXShodHRwOi8vYWR2LXIuaGFkLmNvLm56L1N0eWxlLmh0bWwpLgoKPiA8aSBjbGFzcz0iZmFzIGZhLXF1b3RlLXJpZ2h0Ij48L2k+IEdvb2QgY29kaW5nIHN0eWxlIGlzIGxpa2UgdXNpbmcgY29ycmVjdCBwdW5jdHVhdGlvbi4gPGJyPiBZb3VjYW5tYW5hZ2V3aXRob3V0aXRidXRpdHN1cmVtYWtlc3RoaW5nc2Vhc2llcnRvcmVhZC4uIC0tIEhhZGxleSBXaWNraGFtCgoKIyMgT2JqZWN0cyBpbiBSCgpCdXQgSSBhbHJlYWR5IGRvIGhhdmUgYSBjYWxjdWxhdG9yLiBXaHkgZG8gSSBuZWVkIFI/IAogIAo+IDxpIGNsYXNzPSJmYSBmYS1oYW5kLW8tcmlnaHQiPjwvaT4gUiBpcyBzbyBtdWNoIG1vcmUhIFIgaXMgYW4gb2JqZWN0LW9yaWVudGVkIHByb2dyYW1taW5nIGxhbmd1YWdlLgoKIyMjIyBXaGF0IGlzIGFuICJvYmplY3QiIGluIFI/CiAgCiAgLSBBbiBvYmplY3QgaXMgYSBmb3JtIHRvIHN0b3JlIHRoZSBkYXRhIHlvdSB3YW50IHRvIHVzZS4KCiMjIyMgV2hhdCBraW5kIG9mIGRhdGEgY2FuIEkgc3RvcmUgYXMgYW4gb2JqZWN0PwogICAgCiAgLSBJbiBSIHRoZXJlIGFyZSB0aHJlZSBtYWluIHR5cGVzIG9mIGRhdGEgeW91IGNhbiBzdG9yZToKICAgICAgLSBOdW1lcmljIChudW1iZXJzKQogICAgICAtIENoYXJhY3RlciAobGV0dGVycy93b3Jkcy9zZW50ZW5jZXMvdGV4dHMsIGNhbGxlZCBzdHJpbmdzKQogICAgICAtIExvZ2ljYWwgKFRSVUUvRkFMU0Ugc3RhdGVtZW50cykKICAtIFRoZXNlIGFyZSB0aGUgdHlwZXMgeW91IHdpbGwgb2Z0ZW4gZW5jb3VudGVyLgogIC0gSG93ZXZlciwgdGhlcmUgYXJlIG1hbnkgb3RoZXIgcG9zc2libGUgdHlwZXMuCgojIyMjIFNvIGhvdyBjYW4gSSBnZXQgaW5mb3JtYXRpb24gaW50byBhbiBvYmplY3Q/CiAgCiAgLSBTdG9yZSBhbiBvYmplY3QgYnkgdXNpbmcgYDwtYCBhcyBhc3NpZ25tZW50IG9wZXJhdG9yCgoqKkV4YW1wbGVzOioqCgpgYGB7ciBhc3NpZ25tZW50X29wZXJhdG9yLCBldmFsID0gVFJVRSwgZXJyb3I9VFJVRX0KbHVja3lfbnVtYmVyIDwtCiAKIyBOb3cgd2UgY3JlYXRlZCBhbiAobnVtZXJpYykgb2JqZWN0IGNhbGxlZCAibHVja3lfbnVtYmVyIgoKbHVja3lfbnVtYmVyCmBgYAoKVGhlIGBjbGFzcygpYCBjb21tYW5kIGxldHMgdXMgY2hlY2sgdGhlIHR5cGUgb2YgYW4gb2JqZWN0OgoKYGBge3IgY2xhc3NfY29tbWFuZCwgZXZhbCA9IFRSVUUsIGVycm9yPVRSVUV9Cmx1Y2t5X251bWJlciA8LQoKY2xhc3MobHVja3lfbnVtYmVyKQpgYGAKCkxldCdzIHNlZSBob3cgdGhpcyB3b3JrcyBsaXZlLCB0aGlzIHRpbWUgd2l0aCBhIGNoYXJhY3RlciBvYmplY3Q6CgpgYGB7ciBjaGFyYWN0ZXJfb2JqZWN0LCBldmFsID0gVFJVRSwgZXJyb3I9VFJVRX0KZmlyc3RuYW1lIDwtICIiICMgVGhpcyBpcyBhIGNoYXJhY3RlciBvYmplY3QKCmZpcnN0bmFtZQoKY2xhc3MoZmlyc3RuYW1lKQoKbGFzdG5hbWUgPC0gIiIKCmxhc3RuYW1lCmBgYAoKCgojIyBEYXRhIFN0cnVjdHVyZXMKCldoYXQga2luZCBvZiBkYXRhIGNhbiBJIHN0b3JlIGluIFI/IERpZmZlcmVudCB0eXBlcyBvZiBvYmplY3RzIHRoYXQgY2FuIGNvbnRhaW4gZGlmZmVyZW50IHR5cGVzIGFuZCBzZXRzIG9mIGRhdGE6CgogIC0gKipTY2FsYXIqKjogICAgICBudW1iZXJzLCBjaGFyYWN0ZXJzLCBsb2dpY2FsIHZhbHVlcwogIC0gKipWZWN0b3IqKjogICAgICBzZXRzIG9mIHNjYWxhcnMgKHRodXMsIG51bWJlcnMsIGNoYXJhY3RlcnMsIGxvZ2ljYWwpCiAgLSAqKk1hdHJpeCoqOiAgICAgIHR3by1kaW1lbnNpb25hbCBzZXQgb2Ygc2NhbGFycyBvZiBzYW1lIHR5cGUKICAtICoqRGF0YSBmcmFtZSoqOiAgY29sbGVjdGlvbnMgb2YgdmVjdG9ycyBvZiAocG9zc2libHkpIGRpZmZlcmVudCB0eXBlcwogIC0gKipBcnJheSoqOiAgICAgICBtdWx0aWRpbWVuc2lvbmFsIHNldCBvZiBzY2FsYXJzIG9mIHNhbWUgdHlwZQogIC0gKipMaXN0Kio6ICAgICAgICBjb21iaW5hdGlvbnMgb2Ygc2NhbGFycywgdmVjdG9ycywgbWF0cmljZXMuLi4KCldlIHdpbGwgZ28gdGhyb3VnaCBhbGwgb2YgdGhlc2Ugb2JqZWN0IHR5cGVzIGJlbG93LiBPbiB0b3Agb2YgdGhhdCB3ZSB3aWxsIGFsc28gbGVhcm4gaG93IHRvIGNhbGN1bGF0ZSB0aGUgbWVhc3VyZXMgb2YgY2VudHJhbCB0ZW5kZW5jeSBhbmQgdmFyaWFiaWxpdHkgd2l0aCB2ZWN0b3JzLgoKCiMjIyBEYXRhIFN0cnVjdHVyZXMgLSBWZWN0b3JzCgpMZXQncyBzdGFydCB3aXRoIHZlY3RvcnMuIFdlIHdhbnQgYSB2ZWN0b3Igb2YgdGhlIG51bWJlcnMgMSwgMiwgMywgNCBhbmQgNS4gSG93IGRvIEkgYXNzaWduIHRoaXMgc2V0IG9mIG51bWJlcnMgdG8gYSB2ZWN0b3I/Cgo8aSBjbGFzcz0iZmEgZmEtaGFuZC1vLXJpZ2h0Ij48L2k+IFRoZSBgYygpYCBmdW5jdGlvbiBjb21iaW5lcyBzaW5nbGUgdmFsdWVzIHRvIGEgdmVjdG9yOgoKYGBge3IgdmVjfQpleGFtcGxlX3ZlYyA8LSBjKDEsIDIsIDMsIDQsIDUpCgpleGFtcGxlX3ZlYwpgYGAKClRoaXMgYWxzbyB3b3JrcyBmb3IgY2hhcmFjdGVycy9zdHJpbmdzOgoKYGBge3IgY2hhcl92ZWN9CmNvdW50cnlfY29kZSA8LSBjKCJERSIsICJGUiIsICJOTCIsICJVUyIsICJVSyIpCgpjb3VudHJ5X2NvZGUKYGBgCgpBbmQgaXQgYWxzbyB3b3JrcyBmb3IgYSBjb21iaW5hdGlvbiBvZiBudW1iZXJzIGFuZCBjaGFyYWN0ZXJzOgoKYGBge3IgY29tYmkxfQpleGFtcGxlX3ZlYzIgPC0gYygiV2VsY29tZSIsICJ0byIsICJ0aGUiLCAibGFiIiwgImluIiwgIkEiLCA1KQoKZXhhbXBsZV92ZWMyCmBgYAoKV2hhdCBpZiB3ZSBzdGFydCB3aXRoIG51bWJlcnM/CgpgYGB7ciBjb21iaTJ9CmV4YW1wbGVfdmVjMyA8LSBjKDEsIDIsIDMsIDQsIDUsICJSIGNhbiBjb3VudCEiKQoKZXhhbXBsZV92ZWMzCmBgYAoKCjxpIGNsYXNzPSJmYSBmYS1oYW5kLW8tcmlnaHQiPjwvaT4gTm90ZSB0aGF0IGlmIHlvdSBoYXZlIGEgY2hhcmFjdGVyIGZpZWxkIGluIHlvdXIgdmVjdG9yLCBSIHdpbGwgdHVybiBBTEwgdmFsdWVzIGludG8gY2hhcmFjdGVyIGRhdGEhIChZb3UgY2FuIHNlZSB0aGF0IGJ5IHRoZSBxdW90ZXMgYXJvdW5kIHRoZSB2YWx1ZXMpCgpMZXQncyBjaGVjayB0aGUgdHlwZSBvZiBkYXRhIGJ5IHVzaW5nIHRoZSBgY2xhc3MoKWAgY29tbWFuZCBvbiBgZXhhbXBsZV92ZWMzYC4KCmBgYHtyIGNvbWJpM30KZXhhbXBsZV92ZWMzIDwtIGMoMSwgMiwgMywgNCwgNSwgIlIgY2FuIGNvdW50ISIpCgpjbGFzcyhleGFtcGxlX3ZlYzMpCmBgYAoKWW91IGNhbiB1c2UgbWF0aGVtYXRpY2FsIGZ1bmN0aW9ucyBvbiBlYWNoIGVsZW1lbnQgaW4gbnVtZXJpYyB2ZWN0b3JzL21hdHJpY2VzIGV0Yy4KCmBgYHtyIGZ1bmN0aW9uc19vYmplY3RzMX0KZXhhbXBsZV92ZWMgPC0gYygxLCAyLCAzLCA0LCA1KQoKc3FydChleGFtcGxlX3ZlYykgIyBUYWtlIHRoZSBzcXVhcmUgcm9vdCBvZiBlYWNoIGVsZW1lbnQgaW4gZXhhbXBsZV92ZWMKYGBgCgpXaGF0IGFib3V0IG11bHRpcGxpY2F0aW9uPwoKYGBge3IgZnVuY3Rpb25zX29iamVjdHMzfQpleGFtcGxlX3ZlYyA8LSBjKDEsIDIsIDMsIDQsIDUpCgpleGFtcGxlX3ZlYyAqIDEwCmBgYAoKVGhlcmUgYXJlIGFsc28gc29tZSBmdW5jdGlvbnMgdGhhdCB5b3UgY2FuIHVzZSBvbiB0aGUgd2hvbGUgdmVjdG9yLgoKYGBge3IgZnVuY3Rpb25zX29iamVjdHM0fQpleGFtcGxlX3ZlYyA8LSBjKDEsIDIsIDMsIDQsIDUpCgpzdW0oZXhhbXBsZV92ZWMpICMgUXVlc3Rpb246IFdoYXQgZG9lcyBzdW0oKSBkbz8KCmxlbmd0aChleGFtcGxlX3ZlYykgIyBRdWVzdGlvbjogV2hhdCBkb2VzIGxlbmd0aCgpIGRvPwpgYGAKCgojIyMgRGF0YSBTdHJ1Y3R1cmVzIC0gTWF0cmljZXMKCjxpIGNsYXNzPSJmYSBmYS1oYW5kLW8tcmlnaHQiPjwvaT4gTWF0cmljZXMgaW4gUiBhcmUgdHdvLWRpbWVuc2lvbmFsIHRhYmxlIG9iamVjdHMuIEluIFIsIG1hdHJpY2VzIGFyZSBhbHdheXMgcm93IGJ5IGNvbHVtbi4gTGlrZSAqKnIqKm9sbGVyICoqYyoqb2FzdGVyLCAqKlIqKm9tYW4gKipDKiphdGhvbGljIG9yICoqUioqYXkgKipDKipoYXJsZXMpLgoKSW4gYSBtYXRyaXgsIGFsbCBkYXRhIG11c3QgYmUgb2YgdGhlIHNhbWUgdHlwZS4gSWYgeW91IG1peCBudW1lcmljIGFuZCBjaGFyYWN0ZXIgZW50cmllcywgdGhlIG1hdHJpeCB3aWxsIGJlIGFsbCBjaGFyYWN0ZXIganVzdCBsaWtlIGluIGEgdmVjdG9yLgoKSG93IGRvIEkgY3JlYXRlIGEgbWF0cml4IGluIFI/CgpgYGB7ciBtYXQxfQpleGFtcGxlX21hdDEgPC0gbWF0cml4KGMoMSwgMiwgMywgNCwgNSwgNiksCiAgbnJvdyA9IDMsCiAgbmNvbCA9IDIKKQoKZXhhbXBsZV9tYXQxICMgSG93IGRpZCBSIGZpbGwgdGhlIG51bWJlcnMgaW4gdGhlIG1hdHJpeD8KYGBgCgpZb3UgY291bGQgYWxzbyBjaGFuZ2UgdGhlIG9wdGlvbnMgYW4gbGV0IFIgZmlsbCB0aGUgbWF0cml4ICpieSByb3dzKiAoaW5zdGVhZCBvZiBjb2x1bW5zKToKCmBgYHtyIG1hdDJ9CmV4YW1wbGVfbWF0MiA8LSBtYXRyaXgoYygxLCAyLCAzLCA0LCA1LCA2KSwKICBucm93ID0gMywKICBuY29sID0gMiwKICBieXJvdyA9IFQKKQoKZXhhbXBsZV9tYXQyICMgU2VlIHRoZSBkaWZmZXJlbmNlPwpgYGAKCgpPciB5b3UgY291bGQgY3JlYXRlIGEgbWF0cml4IGZyb20gZGlmZmVyZW50IHZlY3RvcnMgYnkgdXNpbmcgY29sdW1uLWJpbmQgb24gdHdvIG9yIG1vcmUgdmVjdG9ycy4gSXQgd29ya3Mgc2ltaWxhciB0byB0aGUgYGMoKWAgZnVuY3Rpb24gYnV0IHdpdGggdmVjdG9ycyBhcyBpbnB1dCBpbnN0ZWFkIG9mIHNjYWxhcnMuCgpMZXQncyBmaXJzdCBjcmVhdGUgdHdvIHZlY3RvcnMgb2YgdGhlIHNhbWUgbGVuZ3RoOgoKYGBge3IgbWF0M30KdmVjMSA8LSBjKDEsIDIsIDMsIDQsIDUsIDYpCgp2ZWMyIDwtIGMoNywgOCwgOSwgMTAsIDExLCAxMikKCiMgQW5kIG5vdyBjb2x1bW4tYmluZCAtIGNiaW5kKCkgLSB0aGUgdHdvIHZlY3RvcnMuCgpleGFtcGxlX21hdDMgPC0gY2JpbmQodmVjMSwgdmVjMikKCmV4YW1wbGVfbWF0MwpgYGAKClNpbWlsYXJseSwgd2UgY2FuIHJvdy1iaW5kIC0tIGByYmluZCgpYCAtLSB0aGUgdHdvIHZlY3RvcnM6CgpgYGB7ciBtYXQ0fQp2ZWMxIDwtIGMoMSwgMiwgMywgNCwgNSwgNikKCnZlYzIgPC0gYyg3LCA4LCA5LCAxMCwgMTEsIDEyKQoKZXhhbXBsZV9tYXQ0IDwtIHJiaW5kKHZlYzEsIHZlYzIpCgpleGFtcGxlX21hdDQKYGBgCgojIyMgRGF0YSBTdHJ1Y3R1cmVzIC0gRGF0YSBmcmFtZXMKCjxpIGNsYXNzPSJmYSBmYS1oYW5kLW8tcmlnaHQiPjwvaT4gRGF0YSBmcmFtZXMgYXJlIHR3by1kaW1lbnNpb25hbCB0YWJsZSBvYmplY3RzLCBqdXN0IGxpa2UgbWF0cmljZXMuIE1vc3QgZGF0YSB5b3Ugd2lsbCBhbmFseXplIGluIFIgd2lsbCBiZSBpbiB0aGlzIGZvcm0uCgpZb3UgY2FuIGNyZWF0ZSBkYXRhIGZyYW1lcyBmcm9tIHZlY3RvcnMganVzdCBsaWtlIGBjYmluZCgpYCB1c2luZyBgZGF0YS5mcmFtZSgpYDoKCmBgYHtyIGRmMDF9CnZlYzEgPC0gYygxLCAyLCAzLCA0LCA1LCA2KQoKdmVjMiA8LSBjKDcsIDgsIDksIDEwLCAxMSwgMTIpCgpleGFtcGxlX2RmMSA8LSBkYXRhLmZyYW1lKHZlYzEsIHZlYzIpCgpleGFtcGxlX2RmMQpgYGAKCkhvd2V2ZXIsIGRhdGEgZnJhbWVzIGFyZSBhbHdheXMgY29sdW1uLWJvdW5kIHZlY3RvcnMuIEluIGEgZGF0YSBmcmFtZSwgZXZlcnl0aGluZyB3aXRoaW4gYSBjb2x1bW4gaGFzIHRvIGJlIG9mIHRoZSBzYW1lIGRhdGEgdHlwZS4gQnV0ICoqeW91IGNhbiBtaXggZGF0YSB0eXBlcyBiZXR3ZWVuIGNvbHVtbnMqKjogCgpgYGB7ciBkZjAyfQp2ZWMxIDwtIGMoMSwgMiwgMywgNCwgNSwgNikKCnZlYzIgPC0gYyg3LCA4LCA5LCAxMCwgMTEsIDEyKQoKdmVjMyA8LQogIGMoCiAgICAiRmlyc3QgUm93IiwKICAgICJTZWNvbmQgUm93IiwKICAgICJUaGlyZCBSb3ciLAogICAgIkZvdXJ0aCBSb3ciLAogICAgIkZpZnRoIFJvdyIsCiAgICAiU2l4dGggUm93IgogICkKCmV4YW1wbGVfZGYyIDwtIGRhdGEuZnJhbWUodmVjMSwgdmVjMiwgdmVjMykKCmV4YW1wbGVfZGYyCmBgYAoKCllvdSBjYW4gYWxzbyBuYW1lIHlvdXIgY29sdW1ucy92YXJpYWJsZXMuIEVpdGhlciB3aGVuIGNyZWF0aW5nIHlvdXIgZGF0YSBmcmFtZToKCmBgYHtyIGRmMDN9CnZlYzEgPC0gYygxLCAyLCAzLCA0LCA1LCA2KQoKdmVjMiA8LSBjKDcsIDgsIDksIDEwLCAxMSwgMTIpCgp2ZWMzIDwtCiAgYygKICAgICJGaXJzdCBSb3ciLAogICAgIlNlY29uZCBSb3ciLAogICAgIlRoaXJkIFJvdyIsCiAgICAiRm91cnRoIFJvdyIsCiAgICAiRmlmdGggUm93IiwKICAgICJTaXh0aCBSb3ciCiAgKQoKZXhhbXBsZV9kZjMgPC0gZGF0YS5mcmFtZSgKICB2YXJpYWJsZV8xdG82ID0gdmVjMSwKICB2YXJpYWJsZV83dG8xMiA9IHZlYzIsCiAgdmFyaWFibGVfcm93cyA9IHZlYzMKKQoKZXhhbXBsZV9kZjMKYGBgCgpPciBieSByZW5hbWluZyBhbiBleGlzdGluZyBkYXRhIGZyYW1lLgoKYGBge3IgZGYwNH0KdmVjMSA8LSBjKDEsIDIsIDMsIDQsIDUsIDYpCgp2ZWMyIDwtIGMoNywgOCwgOSwgMTAsIDExLCAxMikKCnZlYzMgPC0KICBjKAogICAgIkZpcnN0IFJvdyIsCiAgICAiU2Vjb25kIFJvdyIsCiAgICAiVGhpcmQgUm93IiwKICAgICJGb3VydGggUm93IiwKICAgICJGaWZ0aCBSb3ciLAogICAgIlNpeHRoIFJvdyIKICApCgpleGFtcGxlX2RmMyA8LSBkYXRhLmZyYW1lKHZlYzEsIHZlYzIsIHZlYzMpCgoKIyBSZW5hbWUgdGhlIHZhcmlhYmxlcyBvZiBhbiBleGlzdGluZyBkYXRhIGZyYW1lCgpuYW1lcyhleGFtcGxlX2RmMykgPC0gYygidmFyaWFibGUuMSIsICJ2YXJpYWJsZS4yIiwgInZhcmlhYmxlLjMiKQoKZXhhbXBsZV9kZjMKYGBgCgpgYGB7ciAiZXhhbXBsZV9kZjNfc2V0dXAifQp2ZWMxIDwtIGMoMSwgMiwgMywgNCwgNSwgNikKCnZlYzIgPC0gYyg3LCA4LCA5LCAxMCwgMTEsIDEyKQoKdmVjMyA8LQogIGMoCiAgICAiRmlyc3QgUm93IiwKICAgICJTZWNvbmQgUm93IiwKICAgICJUaGlyZCBSb3ciLAogICAgIkZvdXJ0aCBSb3ciLAogICAgIkZpZnRoIFJvdyIsCiAgICAiU2l4dGggUm93IgogICkKCmV4YW1wbGVfZGYzIDwtIGRhdGEuZnJhbWUodmVjMSwgdmVjMiwgdmVjMykKCm5hbWVzKGV4YW1wbGVfZGYzKSA8LSBjKCJ2YXJpYWJsZS4xIiwgInZhcmlhYmxlLjIiLCAidmFyaWFibGUuMyIpCmBgYAoKCldlIGNhbiBhbHNvIGFkZCBhIG5ldyB2YXJpYWJsZSB0byBhbiBleGlzdGluZyBkYXRhIGZyYW1lLiBXZSBzaW1wbHkgY3JlYXRlIGEgZGF0YSBmcmFtZSB3aGljaCBjb25zaXN0cyBvZiBhIGRhdGEgZnJhbWUgYW5kIGEgdmVjdG9yOgoKYGBge3IgZGYwNSwgZXhlcmNpc2Uuc2V0dXA9ImV4YW1wbGVfZGYzX3NldHVwIn0KZXhhbXBsZV9kZjQgPC0KICBkYXRhLmZyYW1lKGV4YW1wbGVfZGYzLCAKICAgICAgICAgICAgIHZhcmlhYmxlXzQgPSBjKDkwLCA5MSwgOTIsIDkzLCA5NCwgOTUpKQoKZXhhbXBsZV9kZjQKYGBgCgoKIyMjIERhdGEgU3RydWN0dXJlcyAtIEFycmF5cwoKVGhlc2UgYXJlIGxpa2UgbWF0cmljZXMsIGV4Y2VwdCB0aGF0IHRoZXkgYXJlIHR5cGljYWxseSB0aHJlZS1kaW1lbnNpb25hbC4gWW91J3JlIG5vdCBnb2luZyB0byBzZWUgbWFueSBvZiB0aGVzZSwgYnV0IHdlJ2xsIGludHJvZHVjZSB0aGVtIGZvciBjb21wbGV0ZW5lc3MuIEhlcmUgaXMgYW4gaWxsdXN0cmF0aW9uIG9mIHdoYXQgYSB0aHJlZS1kaW1lbnNpb25hbCBhcnJheSBjb3VsZCBvb2sgbGlrZToKCiFbXShodHRwczovL3d3dy5tYXRod29ya3MuY29tL21hdGxhYmNlbnRyYWwvbWxjLWRvd25sb2Fkcy9kb3dubG9hZHMvZWUxNGM0NGQtNjA1Mi00ZDQzLWE4YjktN2JjNGRmNmI4Y2U0LzgxYzU0ZDZmLTU2ZWQtNDlkYi1hZjdmLTM5ZTZiNGRhNWFkZi9pbWFnZXMvc2NyZWVuc2hvdC5qcGcpCgpZb3UgY2FuIHRoaW5rIG9mIDEwIDMgeCA1IGJpbmdvIGNhcmRzLCB0aGF0IGFsbCBkaXNwbGF5IHNwYWNlcyAxIHRocm91Z2ggMTUgZm9yIGV4YW1wbGUsIGFzIGFuIGFycmF5LiBJZiBJIHdlcmUgdG8gZGlzcGxheSB0aGF0IGluIFIsIEkgd291bGQgdXNlIHRoZSBhcnJheSBmdW5jdGlvbiB0byB3cml0ZToKCmBgYHtyIGFycmF5LCByZXN1bHRzID0gImhpZGUifQpiaW5nb19hcnJheSA8LSBhcnJheShzZXEoMSwgMTUsIDEpLCAKICAgICAgICAgICAgICAgICAgICAgZGltID0gYygzLCA1LCAxMCkpCgpiaW5nb19hcnJheQpgYGAKClRoZSBnZW5lcmFsIHN5bnRheCBmb3IgdGhpcyBmdW5jdGlvbiBpcyBgYXJyYXkodmFsdWVzIHlvdSB3YW50IHRvIGFycmF5LCBkaW0gPSAocm93LCBjb2x1bW4sIGhlaWdodCkpYC4KCiMjIyBEYXRhIFN0cnVjdHVyZXMgLSBMaXN0cwoKTGlzdCBvYmplY3RzIGNhbiBjb250YWluIGEgc2VyaWVzIG9mIHRoZSBvdGhlciBvYmplY3RzIHdlIGp1c3QgbGVhcm5lZCBhYm91dC4gQSBzaW5nbGUgbGlzdCBjYW4gY29udGFpbiBhIHZhbHVlLCBhIHZlY3RvciwgYSBtYXRyaXgsIEFORCBhIGRhdGFmcmFtZSAtIG9yIG1hbnkgb2YgZWFjaCEKCkhvdyBkbyBJIG1ha2UgYSBsaXN0PwoKPGkgY2xhc3M9ImZhIGZhLWhhbmQtby1yaWdodCI+PC9pPiBVc2UgdGhlIGBsaXN0KClgIGZ1bmN0aW9uIQogICAgCmBgYHtyIGxpc3QsIHJlc3VsdHMgPSAiaGlkZSJ9CiMgY3JlYXRlIGEgdmVjdG9yCmV4YW1wbGVfdmVjIDwtIGMoMSwgMiwgMywgNCwgNSwgNiwgNywgOCkKCiMgY3JlYXRlIGEgbWF0cml4CmV4YW1wbGVfbWF0IDwtIG1hdHJpeChjKDEsIDIsIDMsIDQsIDUsIDYpLAogICAgICAgICAgICAgICAgICAgICAgbnJvdyA9IDMsCiAgICAgICAgICAgICAgICAgICAgICBuY29sID0gMikKCiMgY3JlYXRlIGFuIGFycmF5CmV4YW1wbGVfYXJyYXkgPC0gYXJyYXkoc2VxKDEsIDE1LCAxKSwgZGltID0gYygzLCA1LCAxMCkpCgpleGFtcGxlX3ZlYzMgPC0gYygxLCAyLCAzLCA0KQoKCiMjIFN0b3JlIGFsbCBvYmplY3RzIGluIGEgbGlzdAoKZXhhbXBsZV9saXN0IDwtIGxpc3QoZXhhbXBsZV92ZWMsIGV4YW1wbGVfbWF0LCBleGFtcGxlX2FycmF5KQoKZXhhbXBsZV9saXN0CmBgYAoKIyMgU2VsZWN0aW5nIGVsZW1lbnRzIGluIGEgdmVjdG9yLCBtYXRyaXggb3IgZGF0YS5mcmFtZQoKU29tZXRpbWVzIHdlIHdhbnQgdG8gc2VsZWN0IHNpbmdsZSBvciBtdWx0aXBsZSBkYXRhIGVudHJpZXMgZnJvbSBvdXIgb2JqZWN0cy4gV2UgY2FuIGRvIHRoaXMgYnkgc2VsZWN0aW5nIGVsZW1lbnRzIHZpYSBgW11gLgoKTGV0J3MgZmlyc3QgZG8gaXQgd2l0aCBhIHZlY3Rvci4gUmVtZW1iZXIgb3VyIGNvdW50cnlfY29kZSB2ZWN0b3I/CgpgYGB7ciBzZWxlY3Rpb24xfQpjb3VudHJ5X2NvZGUgPC0gYygiREUiLCAiRlIiLCAiTkwiLCAiVVMiLCAiVUsiKQoKY291bnRyeV9jb2RlCmBgYAoKCmBgYHtyIGNvdW50cnlfY29kZV9zZXR1cH0KY291bnRyeV9jb2RlIDwtIGMoIkRFIiwgIkZSIiwgIk5MIiwgIlVTIiwgIlVLIikKYGBgCgoKTGV0J3Mgc2F5IHdlIG9ubHkgd2FudCB0byBzZWxlY3QgdGhlICJVUyIuIFdlIGNhbiBhY2hpZXZlIHRoaXMgYnkgYWNjZXNzaW5nIHRoZSB2YWx1ZSB2aWEgaXRzIHBvc2l0aW9uIGluIHRoZSB2ZWN0b3I6CgpgYGB7ciBzZWxlY3Rpb24yfQpjb3VudHJ5X2NvZGVbNF0KYGBgCgpOb3cgd2Ugd2FudCB0byBzZWxlY3QgYWxsIHZhbHVlcyBidXQgdGhlICJVUyI6CgpgYGB7ciBzZWxlY3Rpb24zfQpjb3VudHJ5X2NvZGVbLTRdCmBgYAoKWW91IGNhbiBwYXNzIG11bHRpcGxlIGluZGV4ZXMgYXMgYSB2ZWN0b3I6CgpgYGB7ciBzZWxlY3Rpb240fQpjb3VudHJ5X2NvZGVbYygxLCAyLCAzKV0KYGBgCgpgMTozYCBnZW5lcmF0ZXMgdGhlIHZlY3RvciBgYygxLCAyLCAzKWAgYSBiaXQgcXVpY2tlci4KCmBgYHtyIHNlbGVjdGlvbjV9CmNvdW50cnlfY29kZVsxOjNdCmBgYAoKCklmIHdlIHdhbnQgdGhlIHZhbHVlcyAiREUiLCAiRlIiLCBhbmQgIlVTIiwgYSBzZXF1ZW5jZSBkb2VzIG5vdCByZWFsbHkgaGVscC4gQnV0IHdlIGNhbiBwdXQgYSB2ZWN0b3Igd2l0aCBhIGNvbWJpbmF0aW9uIG9mIGEgc2VxdWVuY2UgYW5kIHNvbWUgb3RoZXIgdmFsdWVzIGluIHRoZSBzcXVhcmUgYnJhY2tldHM6CgpgYGB7ciBzZWxlY3Rpb242fQpjb3VudHJ5X2NvZGVbYygxOjIsIDQpXQpgYGAKCiMjIyMgU2VsZWN0aW5nIGl0ZW1zIGluIHR3by1kaW1lbnNpb25hbCBvYmplY3RzCgpXZSBjYW4gYWNjZXNzIHZhbHVlcyBvZiBhIG1hdHJpeCBzaW1pbGFybHkuIEhvd2V2ZXIsIHdlIG5lZWQgdG8gdGhpbmsgb2Ygb25lIGFkZGl0aW9uYWwgZGltZW5zaW9uLiAKCmBgYHtyIG1hdH0KZXhhbXBsZV9tYXQgPC0gbWF0cml4KGMoMSwgMiwgMywgNCwgNSwgNiksCiAgICAgICAgICAgICAgICAgICAgICBucm93ID0gMywKICAgICAgICAgICAgICAgICAgICAgIG5jb2wgPSAyKQoKZXhhbXBsZV9tYXQKYGBgCgoKR2VuZXJhbGx5LCB3ZSB0eXBlIGBvYmplY3Rbcm93LCBjb2x1bW5dYCB0byBhY2Nlc3Mgc3BlY2lmaWMgcm93cyBhbmQgY29sdW1ucy4gVG8gc2VlIGhvdyB0aGlzIHdvcmtzLCBsZXQncyBoYXZlIGEgbG9vayBhdCBvdXIgYGV4YW1wbGVfbWF0YDoKCk5vdyB3ZSB3YW50IHRvIGFjY2VzcyB0aGUgdmFsdWUgNi4gSXQncyBpbiB0aGUgdGhpcmQgcm93IGFuZCB0aGUgc2Vjb25kIGNvbHVtbi4KCmBgYHtyIHNlbGVjdGlvbjd9CmV4YW1wbGVfbWF0WzMsIDJdCmBgYAoKV2UgY291bGQgYWxzbyBzZWxlY3QgYW4gZW50aXJlIGNvbHVtbiAoYW5kIHVzZSBpdCBsaWtlIGEgdmVjdG9yKS4KCmBgYHtyIHNlbGVjdGlvbjh9CmV4YW1wbGVfbWF0WywgMl0KYGBgCgoKQnkgYWNjZXNzaW5nIHZhbHVlcyB3aXRoIHRoZSBgW11gIHNxdWFyZSBicmFja2V0cywgd2UgY291bGQgYWxzbyByZXBsYWNlIHZhbHVlcy4gCkxldCdzIHNheSB3ZSB3YW50IHRvIHJlY29kZSB0aGUgZW50aXJlIGZpcnN0IGNvbHVtbiBpbiBgZXhhbXBsZV9tYXQzYCB0byA5OToKCmBgYHtyIHNlbGVjdGlvbjl9CmV4YW1wbGVfbWF0WywgMV0gPC0gOTkKCmV4YW1wbGVfbWF0CmBgYAoKYGBge3IgbWF0X3NldHVwMn0KZXhhbXBsZV9tYXQgPC0gbWF0cml4KGMoMSwgMiwgMywgNCwgNSwgNiksCiAgICAgICAgICAgICAgICAgICAgICBucm93ID0gMywKICAgICAgICAgICAgICAgICAgICAgIG5jb2wgPSAyKQoKZXhhbXBsZV9tYXRbLCAxXSA8LSA5OQpgYGAKCgpgYGB7ciBzZWxlY3Rpb24xMH0KIyBBbmQgd2Ugd2FudCB0byByZWNvZGUgdGhlIGZpcnN0IGFuZCB0aGUgdGhpcmQgdmFsdWUgaW4gdGhlIHNlY29uZCBjb2x1bW4KIyB0byA5MSBhbmQgMTAwCgpleGFtcGxlX21hdFtjKDEsIDMpLCAyXSA8LSBjKDkxLCAxMDApCgpleGFtcGxlX21hdApgYGAKCgojIyMgU2VsZWN0aW9uIHdpdGggY29uZGl0aW9ucwoKVGhpcyBpcyBhIGdvb2Qgc3RhcnQgdG8gc2VsZWN0IGFuZCByZWNvZGUgZGF0YSBpbiBhbiBvYmplY3QuIApIb3dldmVyLCBpdCBtaWdodCBiZSBhIGJpdCBleGhhdXN0aW5nIChtYXliZSBldmVuIGltcG9zc2libGUpIHRvIGFsd2F5cyBsb29rIHVwIHRoZSBleGFjdCBwb3NpdGlvbiBpbiB0aGUgb2JqZWN0LgoKTHVja2lseSwgUiBsZXQncyB1cyBhbHNvIHNlbGVjdCBlbGVtZW50cyBiYXNlZCBvbiBjb25kaXRpb25zLiAKSW5zdGVhZCBvZiB0aGUgcG9zaXRpb24gd2UgcHV0IGEgY29uZGl0aW9uIGluIHRoZSBbXSBzcXVhcmUgYnJhY2tldHMuCgoKIC0gRm9yIHRoaXMgd2UgY2FuIHVzZSBzZXZlcmFsIGNvbmRpdGlvbnM6CiAgICAtIElzIGVxdWFsIHRvOiAgICAgICAgICAgIGA9PWAKICAgIC0gSXMgbm90OiAgICAgICAgICAgICAgICAgYCE9YAogICAgLSBJcyBzbWFsbGVyIHRoYW46ICAgICAgICBgPGAKICAgIC0gSXMgZ3JlYXRlciB0aGFuOiAgICAgICAgYD5gCiAgICAtIElzIHNtYWxsZXIgb3IgZXF1YWwgdG86IGA8PWAKICAgIC0gSXMgZ3JlYXRlciBvciBlcXVhbCB0bzogYD49YAoKIC0gQ29uZGl0aW9ucyBjYW4gYmUgY29tYmluZWQgd2l0aCBhbmQgYW5kL29yIG9yIHN0YXRlbWVudHMKICAgIC0gQU5EOiBgJmAKICAgIC0gT1I6ICBgfGAKICAgIApTbyBob3cgZG8gY29uZGl0aW9ucyB3b3JrPyBMZXQncyBjcmVhdGUgYSBtYXRyaXggdG8gd29yayB3aXRoCgpgYGB7ciBjb25kMH0KdmVjMSA8LSBjKDEsIDIsIDMsIDQsIDUsIDYpCgp2ZWMyIDwtIGMoNywgOCwgOSwgMTAsIDExLCAxMikKCiMgQW5kIG5vdyBjb2x1bW4tYmluZCAoY2JpbmQoKSkgdGhlIHR3byB2ZWN0b3JzLgoKZXhhbXBsZV9tYXQgPC0gY2JpbmQodmVjMSwgdmVjMikKCmV4YW1wbGVfbWF0CmBgYAoKCmBgYHtyIGNvbmRpdGlvbl9zZXR1cDF9CnZlYzEgPC0gYygxLCAyLCAzLCA0LCA1LCA2KQoKdmVjMiA8LSBjKDcsIDgsIDksIDEwLCAxMSwgMTIpCgojIEFuZCBub3cgY29sdW1uLWJpbmQgKGNiaW5kKCkpIHRoZSB0d28gdmVjdG9ycy4KCmV4YW1wbGVfbWF0IDwtIGNiaW5kKHZlYzEsIHZlYzIpCmBgYAoKCmBgYHtyIGNvbmQxfQpleGFtcGxlX21hdCA+IDkgIyBUaGlzIHJldHVybnMgVFJVRSBvciBGQUxTRSBmb3IgZWFjaCB2YWx1ZSBpbiB0aGUgb2JqZWN0LgpgYGAKCgpOb3cgaWYgd2UgcHV0IHRoaXMgY29uZGl0aW9uIGluIHNxdWFyZSBicmFja2V0cyB3ZSBnZXQgdGhlIHZhbHVlcyBmb3Igd2hpY2ggdGhlIGNvbmRpdGlvbiBpcyB0cnVlLgpgYGB7ciBjb25kMn0KZXhhbXBsZV9tYXRbZXhhbXBsZV9tYXQgPiA5XQpgYGAKCiMjIFdvcmtpbmcgd2l0aCBkYXRhLmZyYW1lcwoKV29ya2luZyB3aXRoIGRhdGEgZnJhbWVzIGlzIHNpbWlsYXIgdG8gd29ya2luZyB3aXRoIG1hdHJpY2VzIGFuZCB2ZWN0b3JzLgoKIyMjIExvYWRpbmcgYW5kIG1hbmlwdWxhdGluZyBkYXRhCgpVc3VhbGx5IChhbmQgZXNwZWNpYWxseSBmb3IgdGhpcyBjbGFzcykgd2Ugd2FudCB0byB3b3JrIHdpdGggZXhpc3RpbmcgZGF0YXNldHMuIFIga25vd3MgYW5kIGNhbiBsb2FkIG1vc3Qgb2YgdGhlIHN0YW5kYXJkIGZvcm1hdHMgb2YgZGF0YXNldHMsIGxpa2UgYC5jc3ZgLCBgLnhsc3hgIChFeGNlbCksIGAuZHRhYCAoU3RhdGEpLCBgLnNhdmAgKFNQU1MpIGFuZCBtYW55IG1vcmUuIAoKU28gZmFyIHdlIG9ubHkgdXNlZCBSJ3MgYmFzZSBmdW5jdGlvbnMuIEluIG9yZGVyIHRvIHVzZSBzb21lIG1vcmUgc29waGlzdGljYXRlZCBvciBzcGVjaWFsIFIgZnVuY3Rpb25zLCB3ZSBuZWVkIHRvIGxvYWQgbGlicmFyaWVzIG9yIHBhY2thZ2VzIGZpcnN0LiBUaGluayBvZiB0aGVzZSBsaWJyYXJpZXMgYXMgZXh0cmEgYXBwcyB0aGF0IHlvdSBjYW4gbG9hZCBvbiB5b3VyIHNtYXJ0cGhvbmVzIHRvIGV4dGVuZCBpdHMgZnVuY3Rpb25hbGl0eS4gCgpSaWdodCBub3csIHdlIHdhbnQgdG8gbG9hZCB0aGUgZGF0YXNldC4gSW4gb3JkZXIgdG8gdXNlIHRoZSBzdGFuZGFyZCBidXQgZm9yZWlnbiBkYXRhc2V0cyB3ZSBuZWVkIHRoZSAqZm9yZWlnbiogcGFja2FnZS4KCkZpcnN0LCB3ZSB3YW50IHRvIGhhdmUgYSBsb29rIGF0IHdoYXQgdGhlIHBhY2thZ2UgY2FuIGRvLgoKYGBge3J9CnBhY2thZ2VEZXNjcmlwdGlvbigiZm9yZWlnbiIpCgojIE9rIHRoaXMgc2VlbXMgdG8gYmUgdXNlZnVsLiBTbyBsZXQncyBsb2FkIHRoZSBwYWNrYWdlIHRvIHVzZSBpdC4KbGlicmFyeShmb3JlaWduKQpgYGAKCllvdSB3aWxsIG9mdGVuIGNvbWUgYWNyb3NzIGRhdGFzZXRzIHdoaWNoIGFyZSBzdG9yZWQgYXMgU3RhdGEgZGF0YSBmaWxlcy4gVGhvc2UgZmlsZXMgaGF2ZSB0aGUgZXh0ZW5zaW9uIGAuZHRhYC4KClJpZ2h0IG5vdywgd2Ugd2FudCB0byBsb2FkIHRoZSBkYXRhIHNldCBjYWxsZWQgYHdlYXRoZXJfZGF0YV9nZXJtYW55XzIwMjEuZHRhYCB3aGljaCBpcyBhbHJlYWR5IHN0b3JlZCB0aGUgYHJhd19kYXRhYCBmb2xkZXIgaW4gb3VyIGRpcmVjdG9yeToKCmBgYHtyfQp3ZWF0aGVyX2RhdGEgPC0gcmVhZC5kdGEoInJhd19kYXRhL3dlYXRoZXJfZGF0YV9nZXJtYW55XzIwMjEuZHRhIikKYGBgCgoKVGhlIGRhdGEgY29udGFpbnMgeWVhcmx5IHRlbXBlcmF0dXJlIGF2ZXJhZ2VzIG9mIEdlcm1hbiBjaXRpZXMgYXMgd2VsbCBhcyB0aGVpciBnZW9ncmFwaGljYWwgbG9jYXRpb24gKGxvbmdpdHVkZSBhbmQgbGF0aXR1ZGUpLiBJdCBjb21lcyBmcm9tIHRoZSAiRGV1dHNjaGVyIFdldHRlcmRpZW5zdCIgYW5kIHlvdSBjYW4gZmluZCBpdCBbaGVyZV0oaHR0cHM6Ly9jZGMuZHdkLmRlL3BvcnRhbC8yMDIyMDQwMTEwMDUvaW5kZXguaHRtbCkuIE5vdyB0aGF0IHdlIGhhdmUgbG9hZGVkIHRoZSBkYXRhLCB3ZSBjYW4gaGF2ZSBhIGxvb2sgYXQgaXQuCgpXaXRoIGBoZWFkKClgd2UgY2FuIGxvb2sgYXQgdGhlIGZpcnN0IHNpeCByb3dzIG9mIHRoZSBkYXRhIHNldDoKCmBgYHtyIGRmMX0KaGVhZCh3ZWF0aGVyX2RhdGEpCmBgYAoKQnV0IHdlIGNhbiBhbHNvIGxvb2sgYXQgdGhlIGVudGlyZSBkYXRhIHNldDoKCmBgYHtyIGRmMiwgcmVzdWx0cyA9ICJoaWRlIn0Kd2VhdGhlcl9kYXRhCmBgYAoKSWYgd2Ugb25seSB3YW50IHRvIGxvb2sgYXQgdGhlIHZhcmlhYmxlIG5hbWVzLCB3ZSBjYW4gdXNlIGBuYW1lcygpYDoKCmBgYHtyIGRmM30KbmFtZXMod2VhdGhlcl9kYXRhKQpgYGAKCk5vdyB3ZSBjYW4gdXNlIG91ciBzZWxlY3RpbmcgYWJpbGl0aWVzIG9uIGEgZGF0YSBmcmFtZS4gQXMgYmVmb3JlIHdlIGNhbiBzZWxlY3QgZWxlbWVudHMgdmlhIHRoZWlyIG51bWVyaWMgcG9zaXRpb246CgpgYGB7ciBkZjV9CndlYXRoZXJfZGF0YVsxLCAyXSAjIGZpcnN0IHJvdywgc2Vjb25kIGNvbHVtbgpgYGAKCgpgYGB7ciBkZjZ9CndlYXRoZXJfZGF0YVsxOjMsIDFdICMgcm93cyAxLTMsIGZpcnN0IGNvbHVtbgpgYGAKCkFkZGl0aW9uYWxseSwgYXMgY29sdW1ucyB1c3VhbGx5IGhhdmUgbmFtZXMgaW4gZGF0YSBmcmFtZXMsIHdlIGNhbiB1c2UgdGhlIGNvbHVtbiBuYW1lcyB0byBzZWxlY3QgdmFsdWVzIGluIHR3byB3YXlzLgoKRmlyc3QsIHdlIGNhbiBwdXQgdGhlIGNvbHVtbiBuYW1lIGluIHNxdWFyZSBicmFja2V0cyBpbnN0ZWFkIG9mIGEgY29sdW1uIG51bWJlcjoKCmBgYHtyIGRmN30Kd2VhdGhlcl9kYXRhWzEsICJjaXR5Il0KYGBgCgpgYGB7ciBkZjgsIHJlc3VsdHMgPSAiaGlkZSJ9CndlYXRoZXJfZGF0YVssICJtZWFuX3RlbXAiXQpgYGAKCldlIGNhbiBhbHNvIGxvb2sgYXQgdHdvIHZhcmlhYmxlcyBhdCBvbmNlOgoKYGBge3IgZGY5LCByZXN1bHRzID0gImhpZGUifQp3ZWF0aGVyX2RhdGFbLCBjKCJjaXR5IiwgIm1lYW5fdGVtcCIpXQpgYGAKCgpTZWNvbmQsIHdlIGNhbiBhbHNvIHNlbGVjdCBhbiBlbnRpcmUgY29sdW1uIGJ5IHVzaW5nIHRoZSBgJGAgb3BlcmF0b3Igd2l0aCB0aGUgY29sdW1uIG5hbWU6IGBkYXRhLmZyYW1lX25hbWUkY29sdW1uX25hbWVgLiBKdXN0IGxpa2UgdGhpczoKCmBgYHtyIGRmMTB9CndlYXRoZXJfZGF0YSRtZWFuX3RlbXAKYGBgCgpDb2x1bW5zIGZyb20gZGF0YSBmcmFtZXMgYXJlIGVzc2VudGlhbGx5IHZlY3RvcnMuIFdlIGNhbiB1c2UgYWxsIHRoZSBvcGVyYXRpb25zIGFuZCBmdW5jdGlvbnMgd2UgY2FuIHVzZSBmb3IgdmVjdG9ycyAoZGVwZW5kaW5nIG9uIHRoZWlyIGNsYXNzLikKCmBgYHtyIGRmMTF9CndlYXRoZXJfZGF0YSRtZWFuX3RlbXBbMV0gIyBGb3IgZXhhbXBsZSwgd2UgY2FuIHNlbGVjdCBhbiBlbGVtZW50IG9mIHRoZSB2ZWN0b3IKYGBgCgpXaGF0IGlmIHdlIHdhbnQgdG8gYWRkIGEgbmV3IHZhcmlhYmxlPyBMZXQncyBjcmVhdGUgYSB2YXJpYWJsZSBuYW1lZCAieW91bmciLgoKYGBge3IgZGYxMn0Kd2VhdGhlcl9kYXRhJGNvbGQgPC0gMAoKIyBXaGF0IGRvZXMgdGhpcyBkbz8KCndlYXRoZXJfZGF0YSRjb2xkCmBgYAoKTm93LCB3ZSB3YW50IHRvIHJlY29kZSAieW91bmciIHRvIDEgZm9yIHBlb3BsZSB3aG8gYXJlIHlvdW5nZXIgdGhhbiAyNS4KCmBgYHtyIGRmMTMsIHJlc3VsdHMgPSAiaGlkZSJ9Cgp3ZWF0aGVyX2RhdGEkY29sZCA8LSAwCgp3ZWF0aGVyX2RhdGEkY29sZFt3ZWF0aGVyX2RhdGEkbWVhbl90ZW1wIDwgOF0gPC0gMQoKIyBMZXQncyBoYXZlIGEgbG9vayBhdCBib3RoIHZhcmlhYmxlczoKCndlYXRoZXJfZGF0YVssIGMoImNpdHkiLCAibWVhbl90ZW1wIiwgImNvbGQiKV0KYGBgCgoKCgojIyBDYWxjdWxhdGluZyBNZWFzdXJlcyBvZiBDZW50cmFsIFRlbmRlbmN5IGFuZCBWYXJpYWJpbGl0eQoKTGV0J3MgbG9vayBhdCB0aGUgTWVhc3VyZXMgb2YgQ2VudHJhbCBUZW5kZW5jeSBhbmQgVmFyaWFiaWxpdHkgZnJvbSB0aGUgbGVjdHVyZSAoc3RhcnRpbmcgYXQgc2xpZGUgMTYpLgoKQ29uc2lkZXIgdGhlIGZvbGxvd2luZyB2ZWN0b3I6CgpgYGB7cn0KZXhhbXBsZV92ZWMgPC0gYygxLCAyLCAzLCA0LCA1KQpgYGAKCgpIb3cgY291bGQgd2UgY2FsY3VsYXRlIHRoZSBtZWFuIG9mIGBleGFtcGxlX3ZlY2A/CgpXZSBjb3VsZCBzaW1wbHkgY2FsY3VsYXRlIGl0ICJieSBoYW5kIjoKCmBgYHtyfQooMSArIDIgKyAzICsgNCArIDUpIC8gNQpgYGAKCkJ1dCB0aGlzIGlzIG5vdCB2ZXJ5IHVzZWZ1bCBpZiB3ZSBsb29rIGF0IGFuIGFjdHVhbCB2ZWN0b3IgaW4gb3VyIGRhdGEgZnJhbWUsIGUuZy4sIG1lYW4gdGVtcGVyYXR1cmU6CgpgYGB7ciBtY3QxfQp3ZWF0aGVyX2RhdGEkbWVhbl90ZW1wCmBgYAoKVHlwaW5nIHVwIGFsbCB0aGUgZW50cmllcyBpbmRpdmlkdWFsbHkgd291bGQgdGFrZSBhIGxvdCBvZiB0aW1lLiBXZSBjb3VsZCB1c2UgdHdvIGZ1bmN0aW9ucyB0aGF0IHdlIGFscmVhZHkgaGF2ZSBzZWVuLCBzdW0gYW5kIGxlbmd0aC4KCmBgYHtyIG1jdDJ9CnN1bSh3ZWF0aGVyX2RhdGEkbWVhbl90ZW1wKSAvIGxlbmd0aCh3ZWF0aGVyX2RhdGEkbWVhbl90ZW1wKQpgYGAKCgpGb3J0dW5hdGVseSwgUiBwcm92aWRlcyBhIG11Y2ggZWFzaWVyIHdheSB0byBjYWxjdWxhdGUgYSBtZWFuOgoKYGBge3IgbWN0M30KbWVhbih3ZWF0aGVyX2RhdGEkbWVhbl90ZW1wKSAjIFRoYXQgd2FzIGVhc3kuCmBgYAoKQnV0IGJlIHN1cmUgdGhhdCB5b3VyIHZlY3RvciBpcyBudW1lcmljLiBDb3VsZCB5b3UgY2FsY3VsYXRlIHRoZSBtZWFuIG9mIGNpdHk/CgpgYGB7ciBtY3Q0fQp3ZWF0aGVyX2RhdGEkY2l0eQpgYGAKCkxldCdzIHRyeSB0byBjYWxjdWxhdGUgdGhlIG1lYW4uCgpgYGB7ciBtY3Q1fQptZWFuKHdlYXRoZXJfZGF0YSRjaXR5KQpgYGAKCkl0IGRvZXMgbm90IHdvcmshIEFuZCBldmVuIGJ5IGhhbmQgd2UgY291bGQgbm90IGNhbGN1bGF0ZSB0aGUgbWVhbiBvZiBjaGFyYWN0ZXIgdmFsdWVkIHZlY3RvcnMuIAoKSGVyZSBpcyBhbiBvdmVydmlldyBvdmVyIGZ1bmN0aW9ucyBmb3IgbWVhc3VyZXMgb2YgY2VudHJhbGl0eSBhbmQgdmFyaWFiaWxpdHk6CgogIC0gTWVhbjogYG1lYW4oKWAKICAtIE1lZGlhbjogYG1lZGlhbigpYAogIC0gVmFyaWFuY2U6IGB2YXIoKWAKICAtIFN0YW5kYXJkIERldmlhdGlvbjogYHNkKClgCiAgLSBSYW5nZTogYHJhbmdlKClgCiAgLSBJbnRlci1xdWFydGlsZSByYW5nZTogYElRUigpYAogIApZb3UgY2FuIHRyeSB0aGVtIG91dCBoZXJlOgoKYGBge3IgbWN0Nn0KIyBNZWRpYW4KCm1lZGlhbih3ZWF0aGVyX2RhdGEkbWVhbl90ZW1wKQoKIyBWYXJpYW5jZQoKdmFyKHdlYXRoZXJfZGF0YSRtZWFuX3RlbXApCgojIFN0YW5kYXJkIGRldmlhdGlvbgoKc2Qod2VhdGhlcl9kYXRhJG1lYW5fdGVtcCkKCiMgUmFuZ2UKCnJhbmdlKHdlYXRoZXJfZGF0YSRtZWFuX3RlbXApCgojIEludGVyIFF1YXJ0aWxlIFJhbmdlIChJUVIpCgpJUVIod2VhdGhlcl9kYXRhJG1lYW5fdGVtcCkKYGBgCgpVbmZvcnR1bmF0ZWx5LCB0aGVyZSBpcyBubyBkaXJlY3QgZnVuY3Rpb24gdG8gZ2V0IHRoZSBtb2RlLgpUaGUgc29sdXRpb25zIHlvdSB3aWxsIGZpbmQgb25saW5lIGFyZSBhbGwgYSBiaXQgYWR2YW5jZWQuIApTbyB0aGUgZWFzaWVzdCBzb2x1dGlvbiBpcyB0byBsb29rIGZvciB0aGUgbW9kZSB1c2luZyBhIGZyZXF1ZW5jeSB0YWJsZS4KCmBgYHtyIG1jdDd9CnRhYmxlKHdlYXRoZXJfZGF0YSRjb2xkKQpgYGAKClRoZSBgdGFibGUoKWAgZnVuY3Rpb24gc2hvd3MgeW91IGhvdyBvZnRlbiBlYWNoIHZhbHVlIGlzIGluIHRoZSB2ZWN0b3IuIFlvdSBjYW4gbm93IGlkZW50aWZ5IHRoZSBtb3N0IGZyZXF1ZW50IHZhbHVlLiAKCgoKIyMgUGxvdHRpbmcgZGF0YQoKTGV0J3MgaGF2ZSBhIHNob3J0IGxvb2sgYXQgb3VyIGRhdGEgYWdhaW4uClJlbWVtYmVyOiBgaGVhZCgpYCBzaG93cyB5b3UgdGhlIGZpcnN0IHNpeCBlbnRyaWVzIG9mIHlvdXIgZGF0YS4gSXQgaXMgdmVyeSB1c2VmdWwgdG8gZ2V0IGEgbG9vayBhdCB0aGUgZGF0YSBzdHJ1Y3R1cmUgd2hlbiB5b3UgaGF2ZSBhIGxvdCBvZiByb3dzIGluIHlvdXIgZGF0YXNldC4KCmBgYHtyfQpoZWFkKHdlYXRoZXJfZGF0YSkKYGBgCgoKIyMjIFBsb3RzIGZvciBiaXZhcmlhdGUgZGlzdHJpYnV0aW9ucwoKIyMjIyBTY2F0dGVycGxvdHMKCk5vdyB3ZSBjYW4gY3JlYXRlIGEgc2ltcGxlIHNjYXR0ZXJwbG90OgoKYGBge3IgdmlzMX0KcGxvdCgKICB4ID0gd2VhdGhlcl9kYXRhJGxvbmdpdHVkZSwKICB5ID0gd2VhdGhlcl9kYXRhJG1lYW5fdGVtcAopCmBgYAoKVG8gZ2V0IGEgbmljZXIgcGxvdCwgd2UgY2FuIGFkanVzdCBtYW55IHRoaW5ncy4gV2Ugc3VnZ2VzdCB0byBhbHdheXMgZXhwbGljaXRseSBtYWtlIHRob3NlIGFkanVzdG1lbnRzIGluIHRoZSBzYW1lIG9yZGVyLgoKYGBge3IgdmlzMn0KcGxvdCgKICB4ID0gd2VhdGhlcl9kYXRhJGxvbmdpdHVkZSwKICB5ID0gd2VhdGhlcl9kYXRhJG1lYW5fdGVtcCwKICB0eXBlID0gInAiLCAjIFRoaXMgZXhwbGljaXRseSBzYXlzIHRoYXQgd2Ugd2FudCBwb2ludHMuIFlvdSBjb3VsZCBhbHNvIHRyeSAibCIuCiAgbWFpbiA9ICJNZWFuIHRlbXBlcmF0dXJlcyBvZiBHZXJtYW4gY2l0aWVzIiwgIyBUaGlzIGFkZHMgYSB0aXRsZSB0byB0aGUgcGxvdAogIHhsYWIgPSAiTG9uZ2l0dWRlIChXZXN0IC0gRWFzdCkiLCAjIFRoaXMgbGFiZWxzIHRoZSB4LWF4aXMuCiAgeWxhYiA9ICJNZWFuIFRlbXBlcmF0dXJlIGluIDIwMjEiLCAjIFdoYXQgZG9lcyB0aGlzIGRvIHRoZW4/CiAgbGFzID0gMSwgIyBUaGlzIGFmZmVjdHMgdGhlIHRpY2sgbGFiZWxzIG9mIHRoZSB5LWF4aXMuCiAgcGNoID0gMTksICMgSGVyZSB3ZSBjaG9vc2Ugd2hhdCBzeW1ib2xzIHdlIHdhbnQgdG8gcGxvdC4KICBjb2wgPSAiYmxhY2siLCAjIFdoYXQgY29sb3Igc2hvdWxkIHRoZSBzeW1ib2xzIGhhdmU/CiAgZnJhbWUgPSBGICMgTm8gYm94IGFyb3VuZCB0aGUgcGxvdC4KKQpgYGAKCiMjIyBBZGRpbmcgQ29sb3IgdG8gUGxvdHMgd2l0aCBWaXJpZGlzCgpXZSBjYW4gYWxzbyBhZGp1c3QgdGhlIGNvbG9ycy4gTGV0J3MgaGlnaGxpZ2h0IE1hbm5oZWltIQoKPiA8aSBjbGFzcz0iZmEgZmEtZ3JhZHVhdGlvbi1jYXAiPjwvaT4gUHJvIFRpcDogVG8gY29sb3IgdXAgeW91ciBkYXRhIHZpc3VhbGl6YXRpb25zLCB1c2UgdGhlIDxhIGhyZWY9Imh0dHBzOi8vY3Jhbi5yLXByb2plY3Qub3JnL3dlYi9wYWNrYWdlcy92aXJpZGlzL3ZpZ25ldHRlcy9pbnRyby10by12aXJpZGlzLmh0bWwiIHN0eWxlPSJjb2xvcjp3aGl0ZSI+dmlyaWRpcy1wYWNrYWdlPC9hPi4gCgpWaXJpZGlzIGNvbG9ycyBtYWtlIGl0IGVhc2llciB0byByZWFkIGJ5IHRob3NlIHdpdGggY29sb3JibGluZG5lc3MgYW5kIHByaW50IHdlbGwgaW4gZ3JleXNjYWxlLiBZb3UgcHJvYmFibHkgZG9uJ3Qgd2FudCB0byBoYXZlIHBsb3RzIGxpa2UgdGhpczoKCiFbXShodHRwczovL2Zsb3dpbmdkYXRhLmNvbS93cC1jb250ZW50L3VwbG9hZHMvMjAxMi8xMS9EaXZpZGVkLW5hdGlvbi5qcGcpCgpXZSBmaXJzdCBuZWVkIGEgdmVjdG9yIHRoYXQgZ2l2ZXMgdXMgdGhlIHJpZ2h0IGNvbG9ycyB3aXRoIHJlc3BlY3QgdG8gdGhlIGNpdHkgdmFyaWFibGUuCgpgYGB7cn0KbGlicmFyeSh2aXJpZGlzKQoKIyB3ZSBuZWVkIHR3byBjb2xvcnMsIHRoaXMgaXMgaG93IHdlIGdldCB0aGVtOgp0d29fY29sb3JzIDwtIHZpcmlkaXMoMikKCnR3b19jb2xvcnMgIyB0aGVzZSBhcmUgc28tY2FsbGVkIEhFWCBjb2xvciBjb2RlcwoKIyB3ZSB1c2UgdGhlIGZpcnN0IGNvbG9yIGZvciBtYWxlcyBhbmQgdGhlIHNlY29uZCBmb3IgZmVtYWxlcwptYW5uaGVpbV9jb2xvciA8LSBpZmVsc2Uod2VhdGhlcl9kYXRhJGNpdHkgPT0gIk1hbm5oZWltIiwgdHdvX2NvbG9yc1sxXSwgdHdvX2NvbG9yc1syXSkKCiMgbGV0J3MgaGF2ZSBhIGxvb2s6CnRhYmxlKG1hbm5oZWltX2NvbG9yKSAKYGBgCgpOb3cgd2UgY2FuIHVzZSB0aGlzIHZlY3RvciB0byBzcGVjaWZ5IHRoZSBjb2xvciByZXNwZWN0aXZlIHRvIE1hbm5oZWltOgoKYGBge3IgdmlzM30KcGxvdCgKICB4ID0gd2VhdGhlcl9kYXRhJGxvbmdpdHVkZSwKICB5ID0gd2VhdGhlcl9kYXRhJG1lYW5fdGVtcCwKICB0eXBlID0gInAiLCAjIFRoaXMgZXhwbGljaXRseSBzYXlzIHRoYXQgd2Ugd2FudCBwb2ludHMuIFlvdSBjb3VsZCBhbHNvIHRyeSAibCIuCiAgbWFpbiA9ICJNZWFuIHRlbXBlcmF0dXJlcyBvZiBHZXJtYW4gY2l0aWVzIiwgIyBUaGlzIGFkZHMgYSB0aXRsZSB0byB0aGUgcGxvdAogIHhsYWIgPSAiTG9uZ2l0dWRlIChXZXN0IC0gRWFzdCkiLCAjIFRoaXMgbGFiZWxzIHRoZSB4LWF4aXMuCiAgeWxhYiA9ICJNZWFuIFRlbXBlcmF0dXJlIGluIDIwMjEiLCAjIFdoYXQgZG9lcyB0aGlzIGRvIHRoZW4/CiAgbGFzID0gMSwgIyBUaGlzIGFmZmVjdHMgdGhlIHRpY2sgbGFiZWxzIG9mIHRoZSB5LWF4aXMuCiAgcGNoID0gMTksICMgSGVyZSB3ZSBjaG9vc2Ugd2hhdCBzeW1ib2xzIHdlIHdhbnQgdG8gcGxvdC4KICBjb2wgPSBtYW5uaGVpbV9jb2xvciwgIyBJbnN0ZWFkIG9mIGp1c3QgYmxhY2sgd2Ugbm93IHVzZSB0aGUgY29sb3IgdmVjdG9yLgogIGZyYW1lID0gRiAjIE5vIGZyYW1lIGFyb3VuZCB0aGUgcGxvdC4KKQpgYGAKCk5vdyB0aGF0IHdlIHVzZSBkaWZmZXJlbnQgY29sb3JzLCB3ZSBhbHNvIG5lZWQgYSBsZWdlbmQgdG8ga25vdyB3aGljaCBjb2xvciBpcyB3aGljaC4KCmBgYHtyIHZpczR9CnBsb3QoCiAgeCA9IHdlYXRoZXJfZGF0YSRsb25naXR1ZGUsCiAgeSA9IHdlYXRoZXJfZGF0YSRtZWFuX3RlbXAsCiAgdHlwZSA9ICJwIiwgIyBUaGlzIGV4cGxpY2l0bHkgc2F5cyB0aGF0IHdlIHdhbnQgcG9pbnRzLiBZb3UgY291bGQgYWxzbyB0cnkgImwiLgogIG1haW4gPSAiTWVhbiB0ZW1wZXJhdHVyZXMgb2YgR2VybWFuIGNpdGllcyIsICMgVGhpcyBhZGRzIGEgdGl0bGUgdG8gdGhlIHBsb3QKICB4bGFiID0gIkxvbmdpdHVkZSAoV2VzdCAtIEVhc3QpIiwgIyBUaGlzIGxhYmVscyB0aGUgeC1heGlzLgogIHlsYWIgPSAiTWVhbiBUZW1wZXJhdHVyZSBpbiAyMDIxIiwgIyBXaGF0IGRvZXMgdGhpcyBkbyB0aGVuPwogIGxhcyA9IDEsICMgVGhpcyBhZmZlY3RzIHRoZSB0aWNrIGxhYmVscyBvZiB0aGUgeS1heGlzLgogIHBjaCA9IDE5LCAjIEhlcmUgd2UgY2hvb3NlIHdoYXQgc3ltYm9scyB3ZSB3YW50IHRvIHBsb3QuCiAgY29sID0gbWFubmhlaW1fY29sb3IsICMgSW5zdGVhZCBvZiBqdXN0IGJsYWNrIHdlIG5vdyB1c2UgdGhlIGNvbG9yIHZlY3Rvci4KICBmcmFtZSA9IEYgIyBObyBmcmFtZSBhcm91bmQgdGhlIHBsb3QuCikKbGVnZW5kKAogICJib3R0b21sZWZ0IiwgIyBMb2NhdGUgdGhlIGxlZ2VuZCBpbiB0aGUgdG9wbGVmdCBjb3JuZXIuCiAgbGVnZW5kID0gYygiTWFubmhlaW0iLCAib3RoZXIiKSwgIyBHaXZlIGl0IGxhYmVscy4KICBwY2ggPSAxOSwgIyBTcGVjaWZ5IHN5bWJvbHMgYXMgaW4gdGhlIHNjYXR0ZXJwbG90LgogIGNvbCA9IHR3b19jb2xvcnMsICMgU3BlY2lmeSBjb2xvcnMuCiAgYnR5ID0gIm4iICMgTm8gYm94IGFyb3VuZCB0aGUgbGVnZW5kLgopCmBgYAoKYGBge3J9CnBsb3QoCiAgeCA9IHdlYXRoZXJfZGF0YSRsb25naXR1ZGUsCiAgeSA9IHdlYXRoZXJfZGF0YSRtZWFuX3RlbXAsCiAgdHlwZSA9ICJwIiwgIyBUaGlzIGV4cGxpY2l0bHkgc2F5cyB0aGF0IHdlIHdhbnQgcG9pbnRzLiBZb3UgY291bGQgYWxzbyB0cnkgImwiLgogIG1haW4gPSAiTWVhbiB0ZW1wZXJhdHVyZXMgb2YgR2VybWFuIGNpdGllcyIsICMgVGhpcyBhZGRzIGEgdGl0bGUgdG8gdGhlIHBsb3QKICB4bGFiID0gIkxvbmdpdHVkZSAoV2VzdCAtIEVhc3QpIiwgIyBUaGlzIGxhYmVscyB0aGUgeC1heGlzLgogIHlsYWIgPSAiTWVhbiBUZW1wZXJhdHVyZSBpbiAyMDIxIiwgIyBXaGF0IGRvZXMgdGhpcyBkbyB0aGVuPwogIGxhcyA9IDEsICMgVGhpcyBhZmZlY3RzIHRoZSB0aWNrIGxhYmVscyBvZiB0aGUgeS1heGlzLgogIHBjaCA9IDE5LCAjIEhlcmUgd2UgY2hvb3NlIHdoYXQgc3ltYm9scyB3ZSB3YW50IHRvIHBsb3QuCiAgY29sID0gbWFubmhlaW1fY29sb3IsICMgSW5zdGVhZCBvZiBqdXN0IGJsYWNrIHdlIG5vdyB1c2UgdGhlIGNvbG9yIHZlY3Rvci4KICBmcmFtZSA9IEYgIyBObyBmcmFtZSBhcm91bmQgdGhlIHBsb3QuCikKIyB3ZSB3YW50IHRvIGxhYmVsIHRoZSBwb2ludCB0aGF0IHJlZmVycyB0byBNYW5uaGVpbQojIFdlIGNhbiBkbyB0aGF0IHdpdGggdGhlIHRleHQoKSBmdW5jdGlvbiwKIyBCdXQgd2UgbmVlZCB0byBzdWJzZXQgdGhlIGRhdGEsIHNvIHRoYXQgb25seSBNYW5uaGVpbSBnZXRzIGxhYmVsbGVkLAojIGFuZCBubyBvdGhlciBjaXR5CnRleHQoCiAgeCA9IHdlYXRoZXJfZGF0YSRsb25naXR1ZGVbd2VhdGhlcl9kYXRhJGNpdHkgPT0gIk1hbm5oZWltIl0sICMgc3Vic2V0IE1hbm5oZWltCiAgeSA9IHdlYXRoZXJfZGF0YSRtZWFuX3RlbXBbd2VhdGhlcl9kYXRhJGNpdHkgPT0gIk1hbm5oZWltIl0sICMgc3Vic2V0IE1hbm5oZWltCiAgbGFiZWxzID0gIk1hbm5oZWltIiwgIyBsYWJlbCBNYW5uaGVpbSBhcyAiTWFubmhlaW0iCiAgcG9zID0gNCAjIHBvc2l0aW9uIHRoZSBsYWJlbCByaWdodCB0byB0aGUgcG9pbnQKKQpgYGAKCgojIyMgUGxvdHMgZm9yIHVuaXZhcmlhdGUgZGlzdHJpYnV0aW9ucwoKIyMjIyBIaXN0b2dyYW1zCgpOb3cgd2Ugd2FudCB0byB2aXN1YWxpemUgbWVhbiB0ZW1wZXJhdHVyZSB3aXRoIGEgaGlzdG9ncmFtLiBUaGlzIGlzIGhvdyB5b3UgZ2V0IGEgc3RhbmRhcmQgaGlzdG9ncmFtOgoKYGBge3IgdmlzNX0KaGlzdCh4ID0gd2VhdGhlcl9kYXRhJG1lYW5fdGVtcCkgIyBUaGF0J3MgaW50dWl0aXZlLCBidXQgZG9lcyBub3QgbG9vayB0b28gZ3JlYXQKYGBgCgpBZ2Fpbiwgd2UgY2FuIGFkanVzdCBtYW55IHRoaW5ncyB0byBtYWtlIGl0IG5pY2VyLgoKYGBge3IgdmlzNn0KaGlzdCgKICB4ID0gd2VhdGhlcl9kYXRhJG1lYW5fdGVtcCwgIyBGb3IgYSBoaXN0b2dyYW0gd2Ugb25seSBzcGVjaWZ5IHguCiAgYnJlYWtzID0gNTAsICMgc3BlY2lmeSB0aGUgbnVtYmVyIG9mIGJpbnMKICBtYWluID0gIkEgSGlzdG9ncmFtIiwKICB4bGFiID0gIk1lYW4gdGVtcGVyYXR1cmUgaW4gZGVncmVlIENlbHNpdXMiLAogIHlsYWIgPSAiTnVtYmVyIG9mIG9ic2VydmF0aW9ucyIsCiAgbGFzID0gMSwgIyBzaGlmdCB0aGUgeS1heGlzIGxhYmVscyAKICBjb2wgPSB2aXJpZGlzKDEpLCAjIE9uZSBjb2xvciBvbmx5IChmaXJzdCBjb2xvciBmcm9tIHZpcmlkaXMpCiAgYm9yZGVyID0gIndoaXRlIiAjIFRoYXQncyB0aGUgY29sb3Igb2YgdGhlIGJpbiBib3JkZXJzLgopCmBgYAoKIyMjIyBEZW5zaXR5IFBsb3RzCgpXZSBjYW4gYWxzbyBjcmVhdGUgZGVuc2l0eSBwbG90cy4KCmBgYHtyIHZpczd9CnBsb3QoCiAgZGVuc2l0eSh3ZWF0aGVyX2RhdGEkbWVhbl90ZW1wKSwgIyBkZW5zaXR5KCkgdGFrZXMgY2FyZSBvZiB4LCB5IGFuZCB0eXBlLgogIG1haW4gPSAiQSBTaW1wbGUgRGVuc2l0eSBQbG90IiwKICB4bGFiID0gIk1lYW4gdGVtcGVyYXR1cmUgaW4gZGVncmVlIENlbHNpdXMiLAogIHlsYWIgPSAiIiwgIyBUaGUgeS1heGlzIGlzIG5vdCByZWFsbHkgbWVhbmluZ2Z1bCBoZXJlLgogIGNvbCA9IHZpcmlkaXMoMSksCiAgbHdkID0gMiwgIyBDb250cm9sIHRoZSB3aWR0aCBvZiB0aGUgbGluZQogIGZyYW1lID0gRiwKICB5YXh0ID0gIm4iICMgUmVtb3ZlIHRoZSB5LWF4aXMuCikKYGBgCgpBbmQgd2UgY2FuIGFsc28gZmlsbCB0aGUgYXJlIHVuZGVybmVhdGggdGhlIGN1cnZlOgoKYGBge3IgdmlzOH0KcGxvdCgKICBkZW5zaXR5KHdlYXRoZXJfZGF0YSRtZWFuX3RlbXApLCAjIGRlbnNpdHkoKSB0YWtlcyBjYXJlIG9mIHgsIHkgYW5kIHR5cGUuCiAgbWFpbiA9ICJBIFNpbXBsZSBEZW5zaXR5IFBsb3QiLAogIHhsYWIgPSAiTWVhbiB0ZW1wZXJhdHVyZSBpbiBkZWdyZWUgQ2Vsc2l1cyIsCiAgeWxhYiA9ICIiLCAjIFRoZSB5LWF4aXMgaXMgbm90IHJlYWxseSBtZWFuaW5nZnVsIGhlcmUuCiAgY29sID0gdmlyaWRpcygxKSwKICBsd2QgPSAyLCAjIENvbnRyb2wgdGhlIHdpZHRoIG9mIHRoZSBsaW5lCiAgZnJhbWUgPSBGLAogIHlheHQgPSAibiIgIyBSZW1vdmUgdGhlIHktYXhpcy4KKQoKcG9seWdvbihkZW5zaXR5KHdlYXRoZXJfZGF0YSRtZWFuX3RlbXApLCAKICAgICAgICBjb2wgPSB2aXJpZGlzKDEsIGFscGhhID0gMC41KSAjIHNhbWUgY29sb3IgYnV0IDUwJSB0cmFuc3BhcmVudAogICAgICAgICkKYGBgCgojIyMjIC4uLmFuZCBCb3hwbG90cwoKYGBge3IgdmlzOX0KYm94cGxvdCgKICB4ID0gd2VhdGhlcl9kYXRhJG1lYW5fdGVtcCwgIyBBcyBmb3IgaGlzdG9ncmFtcyB3ZSBvbmx5IHNwZWNpZnkgeC4KICBtYWluID0gIkJveHBsb3Qgb2YgTWVhbiB0ZW1wZXJhdHVyZSBpbiBkZWdyZWUgQ2Vsc2l1cyIsCiAgeWxhYiA9ICJNZWFuIHRlbXBlcmF0dXJlIGluIGRlZ3JlZSBDZWxzaXVzIiwKICBsYXMgPSAxLAogIGNvbCA9IHBsYXNtYSgxKSwKICBmcmFtZSA9IEYKKQpgYGAKCk9yIGEgaG9yaXpvbnRhbCBib3hwbG90LgoKYGBge3IgdmlzMTB9CmJveHBsb3QoCiAgeCA9IHdlYXRoZXJfZGF0YSRtZWFuX3RlbXAsCiAgaG9yaXpvbnRhbCA9IFQsICMgV2l0aCBob3Jpem9udGFsID0gVCB3ZSByb3RhdGUgdGhlIGJveHBsb3QuCiAgbWFpbiA9ICJIb3Jpem9udGFsIEJveHBsb3Qgb2YgTWVhbiB0ZW1wZXJhdHVyZSBpbiBkZWdyZWUgQ2Vsc2l1cyIsCiAgeGxhYiA9ICJNZWFuIHRlbXBlcmF0dXJlIGluIGRlZ3JlZSBDZWxzaXVzIiwKICBsYXMgPSAxLAogIGZyYW1lID0gRgopCmBgYAoKWW91IGxlYXJuZWQgaW4gdGhlIGxlY3R1cmUgdGhhdCBib3hwbG90cyBoYXZlIHNvbWUgZGlzYWR2YW50YWdlcy4KCj4gPGkgY2xhc3M9ImZhIGZhLWhhbmQtby1yaWdodCI+PC9pPiBWaW9saW4gcGxvdHMgYXJlIGEgdmVyeSBuaWNlIGFsdGVybmF0aXZlIQoKVGhpcyBpcyBob3cgeW91IGdldCB0aGVtOgoKYGBge3IgdmlzMTF9CmxpYnJhcnkodmlvcGxvdCkKCnZpb3Bsb3QoCiAgeCA9IHdlYXRoZXJfZGF0YSRtZWFuX3RlbXAsCiAgaG9yaXpvbnRhbCA9IFQsICMgV2l0aCBob3Jpem9udGFsID0gVCB3ZSByb3RhdGUgdGhlIGJveHBsb3QuCiAgbWFpbiA9ICJIb3Jpem9udGFsIFZpb2xpbnBsb3Qgb2YgTWVhbiB0ZW1wZXJhdHVyZSBpbiBkZWdyZWUgQ2Vsc2l1cyIsCiAgeGF4dCA9ICJuIiwKICB4bGFiID0gIk1lYW4gdGVtcGVyYXR1cmUgaW4gZGVncmVlIENlbHNpdXMiLAogIGJ0eSA9ICJuIiwKICBheGVzID0gRkFMU0UsCiAgbmFtZXMgPSAiIiwKICBib3JkZXIgPSBOQQopCmBgYAoKCgoKIyMgWW91ciB0dXJuOiBFeGVyY2lzZXMhCgpUaGlzIGhhcyBiZWVuIGEgbG90IGJ1dCBub3cgaXQncyBmaW5hbGx5IHlvdXIgdHVybiEgV2UgaGF2ZSBhIHNlcmllcyBvZiBleGVyY2lzZXMgZm9yIHlvdSB0byB0cnkgb3V0IHRoZSBzdHVmZiB5b3UganVzdCBsZWFybmVkLiAKCj4gIDxpIGNsYXNzPSJmYSBmYS1ncmFkdWF0aW9uLWNhcCI+PC9pPiBQcm8gdGlwOiBDb3B5IHRoZSBsaW5lcyBvZiBjb2RlIHRoYXQgd29ya2VkIGZvciBzb21ldGhpbmcgc2ltaWxhci4gVGhlbiwgYWRqdXN0IHRoZSBjb2RlIGFjY29yZGluZyB0byB5b3VyIHByb2JsZW0uIFRoYXQncyBob3cgY29kaW5nIHdvcmtzIG1vc3Qgb2YgdGhlIHRpbWUhCgoKIyMjIEV4ZXJjaXNlIEk6IENyZWF0aW5nIG9iamVjdHMKCkNyZWF0ZSB0aHJlZSBvYmplY3RzOgoKICAgIDEuIGBteV9sdWNreV9udW1iZXJgIHNob3VsZCBjb250YWluIHlvdXIgbHVja3kgbnVtYmVyLgogICAgMi4gYG15X2ZpcnN0bmFtZWAgc2hvdWxkIGNvbnRhaW4geW91ciBmaXJzdG5hbWUuCiAgICAzLiBgbXlfbGFzdG5hbWVgIHNob3VsZCBjb250YWluIHlvdXIgbGFzdG5hbWUuCgpBZnRlciB5b3UgY3JlYXRlZCB0aGUgb2JqZWN0cywgY2FsbCB0aGVtIHNlcGFyYXRlbHkuIERvbid0IGZvcmdldCB0byBhZGQgY29tbWVudHMgdG8geW91ciBjb2RlLgoKYGBge3IgRXhlcmNpc2VfSV8xLCBldmFsID0gVCwgZXJyb3I9VFJVRX0KCmBgYAoKIyMjIEV4ZXJjaXNlIElJOiBTZWxlY3RpbmcgYW5kIHJlY29kaW5nIGVsZW1lbnRzCgphKSBDcmVhdGUgdHdvIHZlY3RvcnMgYHZlYzFgIGFuZCBgdmVjMmAuCiAgICAtIGB2ZWMxYCBzaG91bGQgY29udGFpbiAxLCA1NiwgMjMsIDg5LCAtMyBhbmQgNSAoaW4gdGhhdCBvcmRlcikuCiAgICAtIGB2ZWMyYCBjb250YWlucyAyNCwgNzgsIDMyLCAyNywgOCBhbmQgMS4KICAgIApiKSBOb3cgc2VsZWN0IGVsZW1lbnRzIG9mIGB2ZWMxYCB0aGF0IGFyZSBncmVhdGVyIHRoYW4gNSBvciBzbWFsbGVyIHRoYW4gMC4KCmMpIE5leHQgc2V0IGB2ZWMxYCB0byB6ZXJvIGlmIGB2ZWMyYCBpcyBncmVhdGVyIHRoYW4gMzAgYW5kIHNtYWxsZXIgb3IgZXF1YWwgdG8gMzIuCgpQbGVhc2Ugc29sdmUgYWxsIHRocmVlIHN0ZXBzIGluIHRoZSBuZXh0IGNvZGUgY2h1bmsuCiAgICAKYGBge3IgRXhlcmNpc2VfSUksIGV2YWwgPSBULCBlcnJvcj1UUlVFfQoKYGBgCgojIyMgIEV4ZXJjaXNlIElJSTogTWFuaXB1bGF0aW5nIGRhdGEKCk5vdyB3ZSB3aWxsIHdvcmsgd2l0aCB0aGUgYHdlYXRoZXJfZGF0YWAgZGF0YSBzZXQuIEl0IGlzIGFscmVhZHkgbG9hZGVkIGZvciB5b3UgYW5kIHlvdSBjYW4gdXNlIGl0IHJpZ2h0IGF3YXkuCgphKSBTaG93IHRoZSB2YXJpYWJsZSBgYWdlYCBpZiBpdCBpcyBvdmVyIDYwLgoKYikgR2VuZXJhdGUgYSBuZXcgdmFyaWFibGUgYW5kIGNhbGwgaXQgYGhvdGAgdGhhdCBpcyB6ZXJvIGZvciAqbWVhbiB0ZW1wZXJhdHVyZSogPCAxMCBhbmQgMSBmb3IgKm1lYW4gdGVtcGVyYXR1cmUqID4gMTAgZGVncmVlIENlbHNpdXMuCgpjKSBIYXZlIGEgbG9vayBhdCB5b3VyIGRhdGEgc2V0LgoKUGxlYXNlIHNvbHZlIGFsbCB0aHJlZSBzdGVwcyBpbiB0aGUgbmV4dCBjb2RlIGNodW5rLgoKYGBge3IgRXhlcmNpc2VfSUlJLCBldmFsID0gVCwgZXJyb3I9VFJVRX0KCmBgYAoKCiMjIyBFeGVyY2lzZSBJVjogU3Vic2V0dGluZwoKQ2FuIHlvdSBmaW5kIHRoZSBob3R0ZXN0IGFuZCBjb2xkZXN0IGNpdHkgaW4gR2VybWFueSAyMDIxPyAKCkhpbnQ6IFRoZSBmdW5jdGlvbnMgYG1pbigpYCBhbmQgYG1heCgpYCBoZWxwIHlvdSB0byBmaW5kIHRoZSBtaW5pbXVtIGFuZCBtYXhpbXVtIHZhbHVlcyBvZiBhIHZlY3RvciBvciB2YXJpYWJsZS4gQ29tYmluZSB0aGF0IHdpdGggeW91ciBuZXdseSBsZWFybmVkIHN1YnNldHRpbmcgc2tpbGxzIGFuZCB5b3UnbGwgZmluZCB0aGUgYW5zd2VyLgoKYGBge3IgRXhlcmNpc2VfSVZfMSwgZXZhbCA9IFQsIGVycm9yPVRSVUV9CgpgYGAKCgojIyMgRXhlcmNpc2UgVjogTWVhc3VyZXMgb2YgY2VudHJhbCB0ZW5kZW5jeQoKV2Ugd2lsbCBjb250aW51ZSB3b3JraW5nIHdpdGggdGhlIHdlYXRoZXIgZGF0YSBzZXQKCmEpIENhbGN1bGF0ZSB0aGUgbWVhbiB2YWx1ZSBvZiBhZ2UgYW5kIHNhdmUgdGhlIHJlc3VsdCBhcyBgbGF0aXR1ZGVgLgogICAgICAKYGBge3IgRXhlcmNpc2VfVl8xLCBldmFsID0gVCwgZXJyb3I9VFJVRX0KCmBgYAoKYikgQ2FsY3VsYXRlIHRoZSB2YXJpYW5jZSBvZiBhZ2UgYW5kIHNhdmUgdGhlIHJlc3VsdCBhcyBgbGF0aXR1ZGVgLgoKYGBge3IgRXhlcmNpc2VfVl8yLCBldmFsID0gVCwgZXJyb3I9VFJVRX0KCmBgYAoKYykgQ2FsY3VsYXRlIHRoZSBzdGFuZGFyZCBkZXZpYXRpb24gb2YgYWdlIGFuZCBzYXZlIHRoZSByZXN1bHQgYXMgYGxhdGl0dWRlYC4KCmBgYHtyIEV4ZXJjaXNlX1ZfMywgZXZhbCA9IFQsIGVycm9yPVRSVUV9CgpgYGAKCgojIyMgIEV4ZXJjaXNlIFZJOiBQbG90dGluZwogICAKYSkgTWFrZSBhIGhpc3RvZ3JhbSBvZiB0aGUgKmxhdGl0dWRlKiB2YXJpYWJsZS4gCgpgYGB7ciBFeGVyY2lzZV9WSV8xLCBldmFsID0gVCwgZXJyb3I9VFJVRX0KCmBgYAogICAKYikgTWFrZSB0aGUgcGxvdCBuaWNlIGxvb2tpbmcgKE5hbWUgdGhlIGF4ZXMsIG1haW4gdGl0bGUsIGNvbG9ycy4uLikKCmBgYHtyIEV4ZXJjaXNlX1ZJXzIsIGV2YWwgPSBULCBlcnJvcj1UUlVFfQoKYGBgCgojIyBSZWNhcAoKV2hhdCB3ZSBsZWFybmVkIGluIHRoaXMgc2Vzc2lvbjoKICAKICAxLiBIb3cgdG8gd29yayB3aXRoIFIgYW5kIEdpdEh1Yi4KICAyLiBBc3NpZ25pbmcgb2JqZWN0cyBpbiBSLgogIDMuIERpZmZlcmVudCBkYXRhIHN0cnVjdHVyZXMgaW4gUi4KICA0LiBIb3cgdG8gZ2V0IHRvIHNpbmdsZSBlbGVtZW50cyB3aXRoaW4gZGF0YSBzdHJ1Y3R1cmVzLgogIDUuIFdvcmtpbmcgd2l0aCBkYXRhIGZyYW1lcy4KICA2LiBIb3cgdG8gbG9hZCBhIGRhdGEgc2V0IGludG8gUi4KICA3LiBIb3cgdG8gbWFrZSBuaWNlIGxvb2tpbmcgcGxvdHMgaW4gUi4KCiMjIFdoYXQgeW91IHdpbGwgZG8gaW4geW91ciBob21ld29yay4KClRoZSBmaXJzdCBsYWIgc2Vzc2lvbiBhbmQgdGhpcyBzY3JpcHQgc2hvdWxkIGVxdWlwIHlvdSB3aXRoIGFsbCB0aGUgdG9vbHMgKGFuZCBsaW5lcyBvZiBjb2RlKSB0byB0YWNrbGUgdGhlIGZpcnN0IGhvbWV3b3JrIGFzc2lnbm1lbnQuCgo+ICA8aSBjbGFzcz0iZmEgZmEtZ3JhZHVhdGlvbi1jYXAiPjwvaT4gQ29weSB0aGUgbGluZXMgb2YgY29kZSB0aGF0IHdvcmtlZCBmb3Igc29tZXRoaW5nIHNpbWlsYXIuIFRoZW4sIGFkanVzdCB0aGUgY29kZSBhY2NvcmRpbmcgdG8geW91ciBwcm9ibGVtLgoKU3Vic3RhbnRpYWxseSwgaW4geW91ciBob21ld29yayB5b3Ugd2lsbCBpbnNwZWN0IGEgZGF0YSBzZXQgb24gVVMgcHJlc2lkZW50aWFsIGVsZWN0aW9ucy4gWW91IHdpbGwgY2FsY3VsYXRlIHNvbWUgbWVhc3VyZXMgb2YgY2VudHJhbCB0ZW5kZW5jeSBhbmQgdmFyaWFiaWxpdHkuIEZpbmFsbHksIHlvdSB3aWxsIHByb2R1Y2Ugc29tZSBuaWNlIHBsb3RzLgoKSXQgaXMgYmVzdCB0byBnZXQgc3RhcnRlZCB3aXRoIHlvdXIgaG9tZXdvcmsgYXMgc29vbiBhcyBwb3NzaWJsZSAoYWZ0ZXIgaXQgd2FzIGhhbmRlZCBvdXQgb24gVHVlc2RheSkuIAoKVHJ5IHRvIHdyaXRlIHRoZSBSIENvZGUgZmlyc3QuIFdlIHdpbGwgcHJvdmlkZSB5b3UgYSBgLlJtZGAgdGVtcGxhdGUgdG8gaGFuZCBpbiB5b3VyIHJlc3VsdHMuCgpJbiBvcmRlciB0byBwYXNzIHRoZSBob21ld29yayBhc3NpZ25tZW50IHlvdSBuZWVkIHRvIHRhY2tsZSBBTEwgcHJvYmxlbXMgb2YgYSBwcm9ibGVtIHNldC4gRm9yIGEgcGFzcyB5b3UgYWxzbyBuZWVkIHRvIGdldCBtb3N0IG9mIHRoZSBwcm9ibGVtcyByaWdodCAob3IgYXQgbGVhc3Qgc2hvdyB1cyB0aGF0IHlvdSB0cmllZCBldmVyeXRoaW5nIHRvIGdldCBpdCByaWdodC4pCgoKIyMjIENsb3NpbmcgcmVtYXJrcy4KCklmIHlvdSBoYXZlIGFueSBxdWVzdGlvbnMgY29uY2VybmluZyB0aGUgbGVjdHVyZSBvciB0aGUgdHV0b3JpYWwgcGxlYXNlIHBvc3QgdGhlbSB0byB0aGUgSUxJQVMgZm9ydW0gb3Igb24gU2xhY2suIFdlIHdpbGwgYW5zd2VyIHRoZW0gb24gYSByZWd1bGFyIGJhc2lzLgoKRG8gbm90IGhlc2l0YXRlIHRvIGNvbWUgdG8gdGhlIG9mZmljZSBob3VycyEKCkFuZCBhbHdheXMgcmVtZW1iZXIgaWYgeW91IGhhdmUgYSBxdWVzdGlvbiwgaXQgaXMgbmV2ZXIgYSBzdHVwaWQgcXVlc3Rpb24uIEluIGZhY3QgbW9zdCBvZiB5b3VyIGZlbGxvdyBzdHVkZW50cyBwcm9iYWJseSBoYXZlIHRoZSBzYW1lIG9yIGEgc2ltaWxhciBxdWVzdGlvbi4gQnkgYXNraW5nIGl0LCBldmVyeW9uZSBpbiB0aGlzIGNsYXNzIHdpbGwgcHJvZml0Lgo=